Merge "Bump splashscreen to 1.2.0-alpha02" into androidx-main
diff --git a/.github/actions/build-single-project/action.yml b/.github/actions/build-single-project/action.yml
index 8c7af75..ecedb70 100644
--- a/.github/actions/build-single-project/action.yml
+++ b/.github/actions/build-single-project/action.yml
@@ -32,8 +32,10 @@
       shell: bash
       run: echo "yes" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "cmake;3.22.1"
     - name: "Install NDK"
+      working-directory: ${{ github.workspace }}
       shell: bash
       run: |
+        set -x
         NDK_VERSION=$(grep "ndkVersion" settings.gradle | awk -F "=" '{gsub(/"| /, ""); print $2}')
         echo "yes" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "ndk;$NDK_VERSION"
     - name: "Install Android SDK Build-Tools"
diff --git a/OWNERS b/OWNERS
index 0bbe0a2..63cb0b9 100644
--- a/OWNERS
+++ b/OWNERS
@@ -39,6 +39,8 @@
 per-file *libraryversions.toml = [email protected]
 # Glance
 per-file *libraryversions.toml = [email protected]
+# AppSearch
+per-file *libraryversions.toml = [email protected], [email protected], [email protected]
 
 # Copybara can self-approve CLs within synced docs.
 per-file docs/** = [email protected]
\ No newline at end of file
diff --git a/activity/activity-compose/src/androidTest/java/androidx/activity/compose/PredictiveBackHandlerTest.kt b/activity/activity-compose/src/androidTest/java/androidx/activity/compose/PredictiveBackHandlerTest.kt
index 1ba51b4..a8e1bee 100644
--- a/activity/activity-compose/src/androidTest/java/androidx/activity/compose/PredictiveBackHandlerTest.kt
+++ b/activity/activity-compose/src/androidTest/java/androidx/activity/compose/PredictiveBackHandlerTest.kt
@@ -172,6 +172,71 @@
         }
     }
 
+    @Test
+    fun testPredictiveBackHandlerDisabledBeforeStart() {
+        val result = mutableListOf()
+        var count by mutableStateOf(2)
+        lateinit var dispatcherOwner: TestOnBackPressedDispatcherOwner
+        lateinit var dispatcher: OnBackPressedDispatcher
+        var started = false
+
+        rule.setContent {
+            dispatcherOwner =
+                TestOnBackPressedDispatcherOwner(LocalLifecycleOwner.current.lifecycle)
+            CompositionLocalProvider(LocalOnBackPressedDispatcherOwner provides dispatcherOwner) {
+                PredictiveBackHandler(count > 1) { progress ->
+                    if (count <= 1) {
+                        started = true
+                    }
+                    progress.collect()
+                    result += "onBack"
+                }
+                dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
+            }
+        }
+
+        // Changing the count right before starting the gesture is received in the
+        // onBackStackStarted callback
+        count = 1
+        dispatcher.startGestureBack()
+
+        rule.runOnIdle { assertThat(started).isTrue() }
+        dispatcher.api34Complete()
+        rule.runOnIdle { assertThat(result).isEqualTo(listOf("onBack")) }
+    }
+
+    fun testPredictiveBackHandlerDisabledAfterStart() {
+        val result = mutableListOf()
+        var count by mutableStateOf(2)
+        lateinit var dispatcherOwner: TestOnBackPressedDispatcherOwner
+        lateinit var dispatcher: OnBackPressedDispatcher
+        var started = false
+
+        rule.setContent {
+            dispatcherOwner =
+                TestOnBackPressedDispatcherOwner(LocalLifecycleOwner.current.lifecycle)
+            CompositionLocalProvider(LocalOnBackPressedDispatcherOwner provides dispatcherOwner) {
+                PredictiveBackHandler(count > 1) { progress ->
+                    if (count <= 1) {
+                        started = true
+                    }
+                    progress.collect()
+                    result += "onBack"
+                }
+                dispatcher = LocalOnBackPressedDispatcherOwner.current!!.onBackPressedDispatcher
+            }
+        }
+
+        dispatcher.startGestureBack()
+        // Changing the count right after starting the gesture is not received in the
+        // onBackStackStarted callback
+        count = 1
+
+        rule.runOnIdle { assertThat(started).isFalse() }
+        dispatcher.api34Complete()
+        rule.runOnIdle { assertThat(result).isEqualTo(listOf("onBack")) }
+    }
+
     @Test(expected = IllegalStateException::class)
     fun testNoCollection() {
         val result = mutableListOf()
diff --git a/activity/activity-compose/src/main/java/androidx/activity/compose/PredictiveBackHandler.kt b/activity/activity-compose/src/main/java/androidx/activity/compose/PredictiveBackHandler.kt
index 1000765..3bdbb96 100644
--- a/activity/activity-compose/src/main/java/androidx/activity/compose/PredictiveBackHandler.kt
+++ b/activity/activity-compose/src/main/java/androidx/activity/compose/PredictiveBackHandler.kt
@@ -76,10 +76,10 @@
     // ensure we don't re-register callbacks when onBack changes
     val currentOnBack by rememberUpdatedState(onBack)
     val onBackScope = rememberCoroutineScope()
+    var onBackInstance: OnBackInstance? = null
 
     val backCallBack = remember {
         object : OnBackPressedCallback(enabled) {
-            var onBackInstance: OnBackInstance? = null
 
             override fun handleOnBackStarted(backEvent: BackEventCompat) {
                 super.handleOnBackStarted(backEvent)
@@ -125,7 +125,13 @@
         }
     }
 
-    LaunchedEffect(enabled) { backCallBack.isEnabled = enabled }
+    LaunchedEffect(enabled) {
+        backCallBack.isEnabled = enabled
+        if (!enabled) {
+            onBackInstance?.close()
+            onBackInstance = null
+        }
+    }
 
     val backDispatcher =
         checkNotNull(LocalOnBackPressedDispatcherOwner.current) {
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/EnterpriseGlobalSearchSessionPlatformCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/EnterpriseGlobalSearchSessionPlatformCtsTest.java
index 968ce31..97f487a 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/EnterpriseGlobalSearchSessionPlatformCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/EnterpriseGlobalSearchSessionPlatformCtsTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+// @exportToFramework:skipFile()
 package androidx.appsearch.cts.app;
 
 import android.content.Context;
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java
index b666e4d..74a03e5 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/cts/app/GenericDocumentCtsTest.java
@@ -20,12 +20,16 @@
 
 import static org.junit.Assert.assertThrows;
 
+import android.os.Build;
+import android.os.Parcel;
+
 import androidx.appsearch.app.EmbeddingVector;
 import androidx.appsearch.app.GenericDocument;
 import androidx.appsearch.flags.CheckFlagsRule;
 import androidx.appsearch.flags.DeviceFlagsValueProvider;
 import androidx.appsearch.flags.Flags;
 import androidx.appsearch.flags.RequiresFlagsEnabled;
+import androidx.test.filters.SdkSuppress;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -1219,4 +1223,39 @@
                 () -> new EmbeddingVector(new float[]{}, "my_model"));
         assertThat(exception).hasMessageThat().contains("Embedding values cannot be empty.");
     }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_GENERIC_DOCUMENT_OVER_IPC)
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    public void testWriteToParcel() {
+        GenericDocument inDoc =
+                new GenericDocument.Builder<>("namespace", "id1", "schema1")
+                        .setScore(42)
+                        .setPropertyString("propString", "Hello")
+                        .setPropertyBytes("propBytes", new byte[][] {{1, 2}})
+                        .setPropertyDocument(
+                                "propDocument",
+                                new GenericDocument.Builder<>("namespace", "id2", "schema2")
+                                        .setPropertyString("propString", "Goodbye")
+                                        .setPropertyBytes("propBytes", new byte[][] {{3, 4}})
+                                        .build())
+                        .build();
+
+        // Serialize the document
+        Parcel parcel = Parcel.obtain();
+        inDoc.writeToParcel(parcel, /* flags= */ 0);
+
+        // Deserialize the document
+        parcel.setDataPosition(0);
+        GenericDocument document = GenericDocument.createFromParcel(parcel);
+        parcel.recycle();
+
+        // Compare results
+        assertThat(document.getPropertyString("propString")).isEqualTo("Hello");
+        assertThat(document.getPropertyBytesArray("propBytes")).isEqualTo(new byte[][] {{1, 2}});
+        assertThat(document.getPropertyDocument("propDocument").getPropertyString("propString"))
+                .isEqualTo("Goodbye");
+        assertThat(document.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
+                .isEqualTo(new byte[][] {{3, 4}});
+    }
 }
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/flags/FlagsTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/flags/FlagsTest.java
index 1428f0f..d4856d7 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/flags/FlagsTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/flags/FlagsTest.java
@@ -113,7 +113,7 @@
     public void testFlagValue_enableSearchSpecSearchStringParameters() {
         assertThat(Flags.FLAG_ENABLE_SEARCH_SPEC_SEARCH_STRING_PARAMETERS)
                 .isEqualTo(
-                        "com.android.appsearch.flags.enable_search_spec_search_spec_strings");
+                        "com.android.appsearch.flags.enable_search_spec_search_string_parameters");
     }
 
     @Test
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CurrentTimeMillisLong.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CurrentTimeMillisLong.java
new file mode 100644
index 0000000..2b1d3f4
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/CurrentTimeMillisLong.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc Value is a non-negative timestamp measured as the number of
+ *            milliseconds since 1970-01-01T00:00:00Z.
+ * @paramDoc Value is a non-negative timestamp measured as the number of
+ *            milliseconds since 1970-01-01T00:00:00Z.
+ * @returnDoc Value is a non-negative timestamp measured as the number of
+ *            milliseconds since 1970-01-01T00:00:00Z.
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public @interface CurrentTimeMillisLong {
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/SystemApi.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/SystemApi.java
new file mode 100644
index 0000000..678d085
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/SystemApi.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+// @exportToFramework:skipFile()
+package androidx.appsearch.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates an API is exposed for use by bundled system applications.
+ *
+ * 

These APIs are not guaranteed to remain consistent release-to-release, + * and are not for use by apps linking against the Android SDK. + * + *

This annotation should only appear on API that is already marked @

hide
.
+ */ +@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE}) +@Retention(RetentionPolicy.RUNTIME) +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +public @interface SystemApi { + enum Client { + /** + * Specifies that the intended clients of a SystemApi are privileged apps. + * This is the default value for {@link #client}. + */ + PRIVILEGED_APPS, + + /** + * Specifies that the intended clients of a SystemApi are used by classes in + *
BOOTCLASSPATH
in mainline modules. Mainline modules can also expose
+ * this type of system APIs too when they're used only by the non-updatable + * platform code. + */ + MODULE_LIBRARIES, + + /** + * Specifies that the system API is available only in the system server process. + * Use this to expose APIs from code loaded by the system server process but + * not in
BOOTCLASSPATH
.
+ */ + SYSTEM_SERVER + } + + /** + * The intended client of this SystemAPI. + */ + Client client() default Client.PRIVILEGED_APPS; + + /** + * Container for {@link SystemApi} that allows it to be applied repeatedly to types. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(TYPE) + @interface Container { + SystemApi[] value(); + } +}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBlobHandle.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBlobHandle.java
index d6ed1c2..2d6501d 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBlobHandle.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBlobHandle.java
@@ -71,7 +71,7 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @Constructor
-    private AppSearchBlobHandle(
+    AppSearchBlobHandle(
             @Param(id = 1) @NonNull byte[] sha256Digest,
             @Param(id = 2) @NonNull String label) {
         mSha256Digest = Preconditions.checkNotNull(sha256Digest);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
index 6de5448..006d119 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
@@ -17,14 +17,19 @@
 package androidx.appsearch.app;
 
 import android.annotation.SuppressLint;
+import android.os.Build;
+import android.os.Parcel;
 import android.util.Log;
 
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appsearch.annotation.CanIgnoreReturnValue;
+import androidx.appsearch.annotation.CurrentTimeMillisLong;
 import androidx.appsearch.annotation.Document;
+import androidx.appsearch.annotation.SystemApi;
 import androidx.appsearch.exceptions.AppSearchException;
 import androidx.appsearch.flags.FlaggedApi;
 import androidx.appsearch.flags.Flags;
@@ -152,6 +157,45 @@
     }
 
     /**
+     * Writes the {@link GenericDocument} to the given {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to write to.
+     * @param flags The flags to use for parceling.
+     * @exportToFramework:hide
+     */
+    // GenericDocument is an open class that can be extended, whereas parcelable classes must be
+    // final in those methods. Thus, we make this a system api to avoid 3p apps depending on it
+    // and getting confused by the inheritability.
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @FlaggedApi(Flags.FLAG_ENABLE_GENERIC_DOCUMENT_OVER_IPC)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public final void writeToParcel(@NonNull Parcel dest, int flags) {
+        Objects.requireNonNull(dest);
+        dest.writeParcelable(mDocumentParcel, flags);
+    }
+
+    /**
+     * Creates a {@link GenericDocument} from a {@link Parcel}.
+     *
+     * @param parcel The {@link Parcel} to read from.
+     * @exportToFramework:hide
+     */
+    // GenericDocument is an open class that can be extended, whereas parcelable classes must be
+    // final in those methods. Thus, we make this a system api to avoid 3p apps depending on it
+    // and getting confused by the inheritability.
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
+    @FlaggedApi(Flags.FLAG_ENABLE_GENERIC_DOCUMENT_OVER_IPC)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @NonNull
+    public static GenericDocument createFromParcel(@NonNull Parcel parcel) {
+        Objects.requireNonNull(parcel);
+        return new GenericDocument(
+                parcel.readParcelable(
+                        GenericDocumentParcel.class.getClassLoader(), GenericDocumentParcel.class));
+    }
+
+    /**
      * Returns the {@link GenericDocumentParcel} holding the values for this
      * {@link GenericDocument}.
      *
@@ -202,7 +246,7 @@
      *
      * 

The value is in the {@link System#currentTimeMillis} time base. */ - /*@exportToFramework:CurrentTimeMillisLong*/ + @CurrentTimeMillisLong public long getCreationTimestampMillis() { return mDocumentParcel.getCreationTimestampMillis(); } @@ -1358,7 +1402,7 @@ @CanIgnoreReturnValue @NonNull public BuilderType setCreationTimestampMillis( - /*@exportToFramework:CurrentTimeMillisLong*/ long creationTimestampMillis) { + @CurrentTimeMillisLong long creationTimestampMillis) { mDocumentParcelBuilder.setCreationTimestampMillis(creationTimestampMillis); return mBuilderTypeInstance; }

diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
index 67550eb..00957811 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportSystemUsageRequest.java
@@ -18,6 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.appsearch.annotation.CanIgnoreReturnValue;
+import androidx.appsearch.annotation.CurrentTimeMillisLong;
 import androidx.core.util.Preconditions;
 
 /**
@@ -79,7 +80,7 @@
      *
      * 

The value is in the {@link System#currentTimeMillis} time base. */ - /*@exportToFramework:CurrentTimeMillisLong*/ + @CurrentTimeMillisLong public long getUsageTimestampMillis() { return mUsageTimestampMillis; } @@ -127,7 +128,7 @@ @CanIgnoreReturnValue @NonNull public ReportSystemUsageRequest.Builder setUsageTimestampMillis( - /*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) { + @CurrentTimeMillisLong long usageTimestampMillis) { mUsageTimestampMillis = usageTimestampMillis; return this; }

diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
index aafcc61..b911919 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/ReportUsageRequest.java
@@ -22,6 +22,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.appsearch.annotation.CanIgnoreReturnValue;
+import androidx.appsearch.annotation.CurrentTimeMillisLong;
 import androidx.appsearch.flags.FlaggedApi;
 import androidx.appsearch.flags.Flags;
 import androidx.appsearch.safeparcel.AbstractSafeParcelable;
@@ -84,7 +85,7 @@
      *
      * 

The value is in the {@link System#currentTimeMillis} time base. */ - /*@exportToFramework:CurrentTimeMillisLong*/ + @CurrentTimeMillisLong public long getUsageTimestampMillis() { return mUsageTimestampMillis; } @@ -127,7 +128,7 @@ @CanIgnoreReturnValue @NonNull public ReportUsageRequest.Builder setUsageTimestampMillis( - /*@exportToFramework:CurrentTimeMillisLong*/ long usageTimestampMillis) { + @CurrentTimeMillisLong long usageTimestampMillis) { mUsageTimestampMillis = usageTimestampMillis; return this; }

diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/flags/Flags.java b/appsearch/appsearch/src/main/java/androidx/appsearch/flags/Flags.java
index 700cfb7..93d8138 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/flags/Flags.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/flags/Flags.java
@@ -80,7 +80,7 @@
      * methods.
      */
     public static final String FLAG_ENABLE_SEARCH_SPEC_SEARCH_STRING_PARAMETERS =
-            FLAG_PREFIX + "enable_search_spec_search_spec_strings";
+            FLAG_PREFIX + "enable_search_spec_search_string_parameters";
 
     /** Enable addTakenActions API in PutDocumentsRequest. */
     public static final String FLAG_ENABLE_PUT_DOCUMENTS_REQUEST_ADD_TAKEN_ACTIONS =
@@ -142,6 +142,10 @@
     public static final String FLAG_ENABLE_BLOB_STORE =
             FLAG_PREFIX + "enable_blob_store";
 
+    /**  Enable {@link androidx.appsearch.app.GenericDocument#writeToParcel}.  */
+    public static final String FLAG_ENABLE_GENERIC_DOCUMENT_OVER_IPC =
+            FLAG_PREFIX + "enable_generic_document_over_ipc";
+
     /** Enable empty batch result fix for enterprise GetDocuments. */
     public static final String FLAG_ENABLE_ENTERPRISE_EMPTY_BATCH_RESULT_FIX =
             FLAG_PREFIX + "enable_enterprise_empty_batch_result_fix";
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/GenericDocumentParcel.java b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/GenericDocumentParcel.java
index 1d407fa..bbfb803 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/GenericDocumentParcel.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/GenericDocumentParcel.java
@@ -24,6 +24,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.appsearch.annotation.CanIgnoreReturnValue;
+import androidx.appsearch.annotation.CurrentTimeMillisLong;
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.AppSearchSession;
 import androidx.appsearch.app.EmbeddingVector;
@@ -193,7 +194,7 @@
     }
 
     /** Returns the creation timestamp of the {@link GenericDocument}, in milliseconds. */
-    /*@exportToFramework:CurrentTimeMillisLong*/
+    @CurrentTimeMillisLong
     public long getCreationTimestampMillis() {
         return mCreationTimestampMillis;
     }
@@ -393,7 +394,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setCreationTimestampMillis(
-                /*@exportToFramework:CurrentTimeMillisLong*/ long creationTimestampMillis) {
+                @CurrentTimeMillisLong long creationTimestampMillis) {
             mCreationTimestampMillis = creationTimestampMillis;
             return this;
         }
diff --git a/appsearch/exportToFramework.py b/appsearch/exportToFramework.py
index b483b72..373cd50 100755
--- a/appsearch/exportToFramework.py
+++ b/appsearch/exportToFramework.py
@@ -32,9 +32,6 @@
 # Replaced with @hide:
 #   
 #
-# Replaced with @CurrentTimeMillisLong:
-#   /*@exportToFramework:CurrentTimeMillisLong*/
-#
 # Removes the text appearing between ifJetpack() and else(), and causes the text appearing between
 # else() and --> to become uncommented, to support framework-only Javadocs:
 #   
@@ -143,10 +140,6 @@
 
         # Add additional imports if required
         imports_to_add = []
-        if '@exportToFramework:CurrentTimeMillisLong' in contents:
-            imports_to_add.append('android.annotation.CurrentTimeMillisLong')
-        if '@exportToFramework:UnsupportedAppUsage' in contents:
-            imports_to_add.append('android.compat.annotation.UnsupportedAppUsage')
         for import_to_add in imports_to_add:
             contents = re.sub(
                     r'^(\s*package [^;]+;\s*)$', r'\1\nimport %s;\n' % import_to_add, contents,
@@ -167,6 +160,12 @@
                     'com.android.server.appsearch.external.localstorage.')
             .replace('androidx.appsearch.flags.FlaggedApi', 'android.annotation.FlaggedApi')
             .replace('androidx.appsearch.flags.Flags', 'com.android.appsearch.flags.Flags')
+            .replace(
+                    'androidx.appsearch.annotation.CurrentTimeMillis',
+                    'android.annotation.CurrentTimeMillis')
+            .replace(
+                    'androidx.appsearch.annotation.SystemApi',
+                    'android.annotation.SystemApi')
             .replace('androidx.appsearch', 'android.app.appsearch')
             .replace(
                     'androidx.annotation.GuardedBy',
@@ -190,9 +189,6 @@
             .replace('@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)', '')
             .replace('Preconditions.checkNotNull(', 'Objects.requireNonNull(')
             .replace('ObjectsCompat.', 'Objects.')
-
-            .replace('/*@exportToFramework:CurrentTimeMillisLong*/', '@CurrentTimeMillisLong')
-            .replace('/*@exportToFramework:UnsupportedAppUsage*/', '@UnsupportedAppUsage')
             .replace('', '@hide')
             .replace('@exportToFramework:hide', '@hide')
             .replace('// @exportToFramework:skipFile()', '')
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
index 35dab5c..6f8298f 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
@@ -29,6 +29,10 @@
         createTempFileFromAsset(prefix = "api24_startup_cold", suffix = ".perfetto-trace")
             .absolutePath
 
+    private val api31ColdStart =
+        createTempFileFromAsset(prefix = "api31_startup_cold", suffix = ".perfetto-trace")
+            .absolutePath
+
     private val commasInSliceNames =
         createTempFileFromAsset(prefix = "api24_commas_in_slice_names", suffix = ".perfetto-trace")
             .absolutePath
@@ -107,6 +111,20 @@
             targetPackageOnly = false,
         )
 
+    @Test
+    fun filterNonTerminatingSlices() =
+        verifyFirstSum(
+            tracePath = api31ColdStart, // arbitrary trace which includes non-termination slices
+            packageName = Packages.TARGET, // ignored
+            sectionName = "wait",
+            expectedFirstMs = 0.00724,
+            expectedMinMs = 0.001615, // filtered out non-terminating -1 duration
+            expectedMaxMs = 357.761234,
+            expectedSumMs = 811.865025,
+            expectedSumCount = 226, // filtered out single case where dur = -1
+            targetPackageOnly = false,
+        )
+
     companion object {
         private fun verifyMetric(
             tracePath: String,
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index 8a2cb2f..519b60e 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -457,6 +457,9 @@
  * )
  * ```
  *
+ * Note that non-terminating slices in the trace (where duration = -1) are always ignored by this
+ * metric.
+ *
  * @see androidx.tracing.Trace.beginSection
  * @see androidx.tracing.Trace.endSection
  * @see androidx.tracing.trace
@@ -553,10 +556,12 @@
         traceSession: PerfettoTraceProcessor.Session
     ): List {
         val slices =
-            traceSession.querySlices(
-                sectionName,
-                packageName = if (targetPackageOnly) captureInfo.targetPackageName else null
-            )
+            traceSession
+                .querySlices(
+                    sectionName,
+                    packageName = if (targetPackageOnly) captureInfo.targetPackageName else null
+                )
+                .filter { it.dur != -1L } // filter out non-terminating slices
 
         return when (mode) {
             Mode.First -> {
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MetricResultExtensions.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MetricResultExtensions.kt
index c78134b..9e03d06 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MetricResultExtensions.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MetricResultExtensions.kt
@@ -64,8 +64,8 @@
             expectedSamples.zip(observedSamples).forEachIndexed { index, pair ->
                 if (abs(pair.first - pair.second) > threshold) {
                     errorString +=
-                        "$name sample $index observed ${pair.first}" +
-                            " more than $threshold from expected ${pair.second}\n"
+                        "$name sample $index observed ${pair.second}, which is" +
+                            " more than $threshold from expected ${pair.first}\n"
                 }
             }
         }
diff --git a/benchmark/gradle-plugin/src/main/resources/scripts/disableJit.sh b/benchmark/gradle-plugin/src/main/resources/scripts/disableJit.sh
new file mode 100755
index 0000000..858a968
--- /dev/null
+++ b/benchmark/gradle-plugin/src/main/resources/scripts/disableJit.sh
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2024 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.
+#
+
+# ADB push intro copied from lockClocks.sh
+if [ "`command -v getprop`" == "" ]; then
+    if [ -n "`command -v adb`" ]; then
+        echo ""
+        echo "Pushing $0 and running it on device..."
+        dest=/data/local/tmp/`basename $0`
+        adb push $0 ${dest}
+        adb shell ${dest} $@
+        adb shell rm ${dest}
+        exit
+    else
+        echo "Could not find adb. Options are:"
+        echo "  1. Ensure adb is on your \$PATH"
+        echo "  2. Use './gradlew lockClocks'"
+        echo "  3. Manually adb push this script to your device, and run it there"
+        exit -1
+    fi
+fi
+
+echo ""
+
+# require root
+if [[ `id` != "uid=0"* ]]; then
+    echo "Not running as root, cannot disable jit, aborting"
+    exit -1
+fi
+
+setprop dalvik.vm.extra-opts "-Xusejit:false"
+stop
+start
+
+DEVICE=`getprop ro.product.device`
+echo "JIT compilation has been disabled on $DEVICE!"
+echo "Performance will be terrible for almost everything! (except e.g. AOT benchmarks)"
+echo "To reenable it (strongly recommended after benchmarking!!!), reboot or run resetDevice.sh"
diff --git a/benchmark/gradle-plugin/src/main/resources/scripts/resetDevice.sh b/benchmark/gradle-plugin/src/main/resources/scripts/resetDevice.sh
new file mode 100755
index 0000000..060f075
--- /dev/null
+++ b/benchmark/gradle-plugin/src/main/resources/scripts/resetDevice.sh
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2024 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.
+#
+
+# ADB push intro copied from lockClocks.sh
+if [ "`command -v getprop`" == "" ]; then
+    if [ -n "`command -v adb`" ]; then
+        echo ""
+        echo "Pushing $0 and running it on device..."
+        dest=/data/local/tmp/`basename $0`
+        adb push $0 ${dest}
+        adb shell ${dest} $@
+        # adb shell rm ${dest} # will fail, not very important
+        exit
+    else
+        echo "Could not find adb. Options are:"
+        echo "  1. Ensure adb is on your \$PATH"
+        echo "  2. Use './gradlew lockClocks'"
+        echo "  3. Manually adb push this script to your device, and run it there"
+        exit -1
+    fi
+fi
+
+DEVICE=`getprop ro.product.device`
+echo ""
+echo "Rebooting $DEVICE, and resetting animation scales!"
+echo "This will re-lock clocks, reenable JIT, and reset animation scale to 1.0"
+
+settings put global window_animation_scale 1.0
+settings put global transition_animation_scale 1.0
+settings put global animator_duration_scale 1.0
+
+reboot # required to relock clocks, and handles reenabling jit since the property won't persist
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index c2a6cc7..cdf3a164 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -22,6 +22,11 @@
 
 repos.addMavenRepositories(repositories)
 
+project.tasks.withType(Jar).configureEach { task ->
+    task.reproducibleFileOrder = true
+    task.preserveFileTimestamps = false
+}
+
 dependencies {
     api(project("plugins"))
 }
diff --git a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
index e9e6568..c615c95 100644
--- a/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/androidTest/java/androidx/camera/camera2/pipe/testing/TestUseCaseCamera.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraDevice
-import android.hardware.camera2.CaptureRequest
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraPipe
@@ -36,7 +35,6 @@
 import androidx.camera.camera2.pipe.integration.config.CameraConfig
 import androidx.camera.camera2.pipe.integration.config.UseCaseCameraConfig
 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
-import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
 import androidx.camera.camera2.pipe.integration.impl.CameraCallbackMap
 import androidx.camera.camera2.pipe.integration.impl.CameraInteropStateCallbackRepository
 import androidx.camera.camera2.pipe.integration.impl.CapturePipeline
@@ -54,7 +52,6 @@
 import androidx.camera.core.impl.CaptureConfig
 import androidx.camera.core.impl.Config
 import androidx.camera.core.impl.DeferrableSurface
-import androidx.camera.core.impl.SessionConfig
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
@@ -172,38 +169,10 @@
                 }
             }
 
-    override var runningUseCases = useCases.toSet()
-
-    override var isPrimary: Boolean = true
-        set(value) {
-            field = value
-        }
-
-    override fun  setParameterAsync(
-        key: CaptureRequest.Key,
-        value: T,
-        priority: Config.OptionPriority
-    ): Deferred {
-        throw NotImplementedError("Not implemented")
-    }
-
-    override fun setParametersAsync(
-        values: Map, Any>,
-        priority: Config.OptionPriority
-    ): Deferred {
-        throw NotImplementedError("Not implemented")
-    }
-
     override fun close(): Job {
         return threads.scope.launch {
             useCaseCameraGraphConfig.graph.close()
             useCaseSurfaceManager.stopAsync().await()
         }
     }
-
-    companion object {
-        fun SessionConfig.toCamera2ImplConfig(): Camera2ImplConfig {
-            return Camera2ImplConfig(implementationOptions)
-        }
-    }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
index 7259c36..26930dd 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombination.kt
@@ -129,10 +129,10 @@
 
         if (dynamicRangeResolver.is10BitDynamicRangeSupported()) {
             generate10BitSupportedCombinationList()
+        }
 
-            if (isUltraHdrSupported()) {
-                generateUltraHdrSupportedCombinationList()
-            }
+        if (isUltraHdrSupported()) {
+            generateUltraHdrSupportedCombinationList()
         }
 
         if (isPreviewStabilizationSupported) {
@@ -194,7 +194,12 @@
             return featureSettingsToSupportedCombinationsMap[featureSettings]!!
         }
         var supportedSurfaceCombinations: MutableList = mutableListOf()
-        if (featureSettings.requiredMaxBitDepth == DynamicRange.BIT_DEPTH_8_BIT) {
+        if (featureSettings.isUltraHdrOn) {
+            // For Ultra HDR output, only the default camera mode is currently supported.
+            if (featureSettings.cameraMode == CameraMode.DEFAULT) {
+                supportedSurfaceCombinations.addAll(surfaceCombinationsUltraHdr)
+            }
+        } else if (featureSettings.requiredMaxBitDepth == DynamicRange.BIT_DEPTH_8_BIT) {
             when (featureSettings.cameraMode) {
                 CameraMode.CONCURRENT_CAMERA ->
                     supportedSurfaceCombinations = concurrentSurfaceCombinations
@@ -213,11 +218,7 @@
         } else if (featureSettings.requiredMaxBitDepth == DynamicRange.BIT_DEPTH_10_BIT) {
             // For 10-bit outputs, only the default camera mode is currently supported.
             if (featureSettings.cameraMode == CameraMode.DEFAULT) {
-                if (featureSettings.isUltraHdrOn) {
-                    supportedSurfaceCombinations.addAll(surfaceCombinationsUltraHdr)
-                } else {
-                    supportedSurfaceCombinations.addAll(surfaceCombinations10Bit)
-                }
+                supportedSurfaceCombinations.addAll(surfaceCombinations10Bit)
             }
         }
         featureSettingsToSupportedCombinationsMap[featureSettings] = supportedSurfaceCombinations
@@ -393,6 +394,11 @@
         isPreviewStabilizationOn: Boolean,
         isUltraHdrOn: Boolean
     ): FeatureSettings {
+        require(!(cameraMode != CameraMode.DEFAULT && isUltraHdrOn)) {
+            "Camera device Id is $cameraId. Ultra HDR is not " +
+                "currently supported in ${CameraMode.toLabelString(cameraMode)} camera mode."
+        }
+
         val requiredMaxBitDepth = getRequiredMaxBitDepth(resolvedDynamicRanges)
         require(
             !(cameraMode != CameraMode.DEFAULT &&
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/Camera2CameraControlCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/Camera2CameraControlCompat.kt
index bf98070a..684ed09 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/Camera2CameraControlCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/Camera2CameraControlCompat.kt
@@ -24,7 +24,6 @@
 import androidx.camera.camera2.pipe.integration.adapter.propagateTo
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.camera2.pipe.integration.impl.Camera2ImplConfig
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.impl.containsTag
 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
@@ -52,7 +51,7 @@
     public fun cancelCurrentTask()
 
     public fun applyAsync(
-        camera: UseCaseCamera?,
+        requestControl: UseCaseCameraRequestControl?,
         cancelPreviousTask: Boolean = true
     ): Deferred
 
@@ -106,11 +105,14 @@
                 ?.cancelSignal("The camera control has became inactive.")
         }
 
-    override fun applyAsync(camera: UseCaseCamera?, cancelPreviousTask: Boolean): Deferred {
+    override fun applyAsync(
+        requestControl: UseCaseCameraRequestControl?,
+        cancelPreviousTask: Boolean
+    ): Deferred {
         val signal: CompletableDeferred = CompletableDeferred()
         val config = synchronized(lock) { configBuilder.build() }
         synchronized(updateSignalLock) {
-            if (camera != null) {
+            if (requestControl != null) {
                 if (cancelPreviousTask) {
                     // Cancel the previous request signal if exist.
                     updateSignal?.cancelSignal()
@@ -122,7 +124,7 @@
                 }
 
                 updateSignal = signal
-                camera.requestControl.setConfigAsync(
+                requestControl.setConfigAsync(
                     type = UseCaseCameraRequestControl.Type.CAMERA2_CAMERA_CONTROL,
                     config = config,
                     tags = mapOf(TAG_KEY to signal.hashCode())
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/EvCompCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/EvCompCompat.kt
index 17c69c4..7901a98 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/EvCompCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/EvCompCompat.kt
@@ -30,7 +30,7 @@
 import androidx.camera.camera2.pipe.integration.config.CameraScope
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.camera2.pipe.integration.impl.ComboRequestListener
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
 import androidx.camera.core.CameraControl
 import dagger.Binds
@@ -49,7 +49,7 @@
 
     public fun applyAsync(
         evCompIndex: Int,
-        camera: UseCaseCamera,
+        requestControl: UseCaseCameraRequestControl,
         cancelPreviousTask: Boolean,
     ): Deferred
 
@@ -97,7 +97,7 @@
 
     override fun applyAsync(
         evCompIndex: Int,
-        camera: UseCaseCamera,
+        requestControl: UseCaseCameraRequestControl,
         cancelPreviousTask: Boolean,
     ): Deferred {
         val signal = CompletableDeferred()
@@ -122,7 +122,9 @@
                 updateListener = null
             }
 
-            camera.setParameterAsync(CONTROL_AE_EXPOSURE_COMPENSATION, evCompIndex)
+            requestControl.setParametersAsync(
+                values = mapOf(CONTROL_AE_EXPOSURE_COMPENSATION to evCompIndex)
+            )
 
             // Prepare the listener to wait for the exposure value to reach the target.
             updateListener =
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompat.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompat.kt
index c04fcf7..6b284cb 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/ZoomCompat.kt
@@ -25,7 +25,7 @@
 import androidx.camera.camera2.pipe.core.Log
 import androidx.camera.camera2.pipe.integration.compat.workaround.getControlZoomRatioRangeSafely
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.internal.ZoomMath.nearZero
 import dagger.Module
 import dagger.Provides
@@ -35,7 +35,10 @@
     public val minZoomRatio: Float
     public val maxZoomRatio: Float
 
-    public fun applyAsync(zoomRatio: Float, camera: UseCaseCamera): Deferred
+    public fun applyAsync(
+        zoomRatio: Float,
+        requestControl: UseCaseCameraRequestControl
+    ): Deferred
 
     /**
      * Returns the current crop sensor region which should be used for converting
@@ -84,11 +87,16 @@
 
     private var currentCropRect: Rect? = null
 
-    override fun applyAsync(zoomRatio: Float, camera: UseCaseCamera): Deferred {
+    override fun applyAsync(
+        zoomRatio: Float,
+        requestControl: UseCaseCameraRequestControl
+    ): Deferred {
         val sensorRect =
             cameraProperties.metadata[CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE]!!
         currentCropRect = computeCropRect(sensorRect, zoomRatio)
-        return camera.setParameterAsync(CaptureRequest.SCALER_CROP_REGION, currentCropRect)
+        return requestControl.setParametersAsync(
+            values = mapOf(CaptureRequest.SCALER_CROP_REGION to (currentCropRect as Any))
+        )
     }
 
     override fun getCropSensorRegion(): Rect =
@@ -129,14 +137,17 @@
     override val maxZoomRatio: Float
         get() = range.upper
 
-    override fun applyAsync(zoomRatio: Float, camera: UseCaseCamera): Deferred {
+    override fun applyAsync(
+        zoomRatio: Float,
+        requestControl: UseCaseCameraRequestControl
+    ): Deferred {
         require(zoomRatio in minZoomRatio..maxZoomRatio)
         val parameters: MutableMap, Any> =
             mutableMapOf(CaptureRequest.CONTROL_ZOOM_RATIO to zoomRatio)
         if (shouldOverrideZoom && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
             Api34Compat.setSettingsOverrideZoom(parameters)
         }
-        return camera.setParametersAsync(parameters)
+        return requestControl.setParametersAsync(values = parameters)
     }
 
     override fun getCropSensorRegion(): Rect =
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ZslDisablerQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ZslDisablerQuirk.kt
index 40f7e51..cad386b 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ZslDisablerQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/ZslDisablerQuirk.kt
@@ -24,9 +24,10 @@
 
 /**
  * QuirkSummary
- * - Bug Id: 252818931, 261744070, 319913852
- * - Description: On certain devices, the captured image has color issue for reprocessing. We need
- *   to disable zero-shutter lag and return false for [CameraInfo.isZslSupported].
+ * - Bug Id: 252818931, 261744070, 319913852, 361328838
+ * - Description: On certain devices, the captured image has color or zoom freezing issue for
+ *   reprocessing. We need to disable zero-shutter lag and return false for
+ *   [CameraInfo.isZslSupported].
  * - Device(s): Samsung Fold4, Samsung s22, Xiaomi Mi 8
  */
 @SuppressLint("CameraXQuirksClassDetector")
@@ -34,7 +35,8 @@
 public class ZslDisablerQuirk : Quirk {
 
     public companion object {
-        private val AFFECTED_SAMSUNG_MODEL = listOf("SM-F936", "SM-S901U", "SM-S908U", "SM-S908U1")
+        private val AFFECTED_SAMSUNG_MODEL =
+            listOf("SM-F936", "SM-S901U", "SM-S908U", "SM-S908U1", "SM-F721U1", "SM-S928U1")
 
         private val AFFECTED_XIAOMI_MODEL = listOf("MI 8")
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/EvCompControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/EvCompControl.kt
index 23817fa..7a7b198 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/EvCompControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/EvCompControl.kt
@@ -57,11 +57,11 @@
             compat.step,
         )
 
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
             updateAsync(evCompIndex, cancelPreviousTask = false)
         }
 
@@ -86,9 +86,9 @@
             )
         }
 
-        return useCaseCamera?.let { camera ->
+        return requestControl?.let { requestControl ->
             evCompIndex = exposureIndex
-            compat.applyAsync(exposureIndex, camera, cancelPreviousTask)
+            compat.applyAsync(exposureIndex, requestControl, cancelPreviousTask)
         }
             ?: run {
                 CameraControl.OperationCanceledException("Camera is not active.").let { cancelResult
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FlashControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FlashControl.kt
index 1c9f0e7..dbc0d6b 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FlashControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FlashControl.kt
@@ -53,11 +53,11 @@
     private val torchControl: TorchControl,
     private val useFlashModeTorchFor3aUpdate: UseFlashModeTorchFor3aUpdate,
 ) : UseCaseCameraControl {
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
             setFlashAsync(_flashMode, false)
         }
 
@@ -98,7 +98,7 @@
     ): Deferred {
         val signal = CompletableDeferred()
 
-        useCaseCamera?.let {
+        requestControl?.let {
 
             // Update _flashMode immediately so that CameraControlInternal#getFlashMode()
             // returns correct value.
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
index 9e69cb2..8bfcd72 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/FocusMeteringControl.kt
@@ -41,6 +41,7 @@
 import androidx.camera.core.FocusMeteringResult
 import androidx.camera.core.MeteringPoint
 import androidx.camera.core.Preview
+import androidx.camera.core.UseCase
 import androidx.camera.core.impl.CameraControlInternal
 import com.google.common.util.concurrent.ListenableFuture
 import dagger.Binds
@@ -66,20 +67,20 @@
     private val state3AControl: State3AControl,
     private val threads: UseCaseThreads,
     private val zoomCompat: ZoomCompat,
-) : UseCaseCameraControl, UseCaseCamera.RunningUseCasesChangeListener {
-    private var _useCaseCamera: UseCaseCamera? = null
+) : UseCaseCameraControl, UseCaseManager.RunningUseCasesChangeListener {
+    private var _requestControl: UseCaseCameraRequestControl? = null
 
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
         }
 
-    override fun onRunningUseCasesChanged() {
+    override fun onRunningUseCasesChanged(runningUseCases: Set) {
         // reset to null since preview use case may not be active for current runningUseCases
         previewAspectRatio = null
 
-        _useCaseCamera?.runningUseCases?.forEach { useCase ->
+        for (useCase in runningUseCases) {
             if (useCase is Preview) {
                 useCase.attachedSurfaceResolution?.apply {
                     previewAspectRatio = Rational(width, height)
@@ -119,7 +120,7 @@
     ): ListenableFuture {
         val signal = CompletableDeferred()
 
-        useCaseCamera?.let { useCaseCamera ->
+        requestControl?.let { requestControl ->
             threads.sequentialScope.launch {
                 focusTimeoutJob?.cancel()
                 autoCancelJob?.cancel()
@@ -194,7 +195,7 @@
                          * the CameraGraph and thus may cause extra requests to the camera.
                          */
                         debug { "startFocusAndMetering: updating 3A regions only" }
-                        useCaseCamera.requestControl.update3aRegions(
+                        requestControl.update3aRegions(
                             aeRegions = aeRegions,
                             afRegions = afRegions,
                             awbRegions = awbRegions,
@@ -217,7 +218,7 @@
                          * If device does support but a region list is empty, it means any previously
                          * set region should be removed, so the no-op METERING_REGIONS_DEFAULT is used.
                          */
-                        useCaseCamera.requestControl.startFocusAndMeteringAsync(
+                        requestControl.startFocusAndMeteringAsync(
                             aeRegions = aeRegions,
                             afRegions = afRegions,
                             awbRegions = awbRegions,
@@ -243,7 +244,7 @@
                 triggerFocusTimeout(autoFocusTimeoutMs, signal)
 
                 if (action.isAutoCancelEnabled) {
-                    triggerAutoCancel(action.autoCancelDurationInMillis, signal, useCaseCamera)
+                    triggerAutoCancel(action.autoCancelDurationInMillis, signal, requestControl)
                 }
             }
         }
@@ -257,7 +258,7 @@
     private fun triggerAutoCancel(
         delayMillis: Long,
         resultToCancel: CompletableDeferred,
-        useCaseCamera: UseCaseCamera,
+        requestControl: UseCaseCameraRequestControl,
     ) {
         autoCancelJob?.cancel()
 
@@ -265,7 +266,7 @@
             threads.sequentialScope.launch {
                 delay(delayMillis)
                 debug { "triggerAutoCancel: auto-canceling after $delayMillis ms" }
-                cancelFocusAndMeteringNowAsync(useCaseCamera, resultToCancel)
+                cancelFocusAndMeteringNowAsync(requestControl, resultToCancel)
             }
     }
 
@@ -365,13 +366,13 @@
 
     public fun cancelFocusAndMeteringAsync(): Deferred {
         val signal = CompletableDeferred()
-        useCaseCamera?.let { useCaseCamera ->
+        requestControl?.let { requestControl ->
             threads.sequentialScope.launch {
                 focusTimeoutJob?.cancel()
                 autoCancelJob?.cancel()
                 cancelSignal?.setCancelException("Cancelled by another cancelFocusAndMetering()")
                 cancelSignal = signal
-                cancelFocusAndMeteringNowAsync(useCaseCamera, updateSignal).propagateTo(signal)
+                cancelFocusAndMeteringNowAsync(requestControl, updateSignal).propagateTo(signal)
             }
         }
             ?: run {
@@ -382,12 +383,12 @@
     }
 
     private suspend fun cancelFocusAndMeteringNowAsync(
-        useCaseCamera: UseCaseCamera,
+        requestControl: UseCaseCameraRequestControl,
         signalToCancel: CompletableDeferred?,
     ): Deferred {
         signalToCancel?.setCancelException("Cancelled by cancelFocusAndMetering()")
         state3AControl.preferredFocusMode = null
-        return useCaseCamera.requestControl.cancelFocusAndMeteringAsync()
+        return requestControl.cancelFocusAndMeteringAsync()
     }
 
     private fun  CompletableDeferred.setCancelException(message: String) {
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
index 25456dc..da6fcdb 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/State3AControl.kt
@@ -46,12 +46,12 @@
     public val cameraProperties: CameraProperties,
     private val aeModeDisabler: AutoFlashAEModeDisabler,
     private val aeFpsRange: AeFpsRange,
-) : UseCaseCameraControl, UseCaseCamera.RunningUseCasesChangeListener {
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+) : UseCaseCameraControl, UseCaseManager.RunningUseCasesChangeListener {
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
             value?.let {
                 val previousSignals =
                     synchronized(lock) {
@@ -61,15 +61,21 @@
 
                 invalidate() // Always apply the settings to the camera.
 
-                synchronized(lock) { updateSignal }
-                    ?.let { newUpdateSignal ->
-                        previousSignals.forEach { newUpdateSignal.propagateTo(it) }
-                    } ?: run { previousSignals.forEach { it.complete(Unit) } }
+                synchronized(lock) { updateSignal }?.propagateToAll(previousSignals)
+                    ?: run { for (signals in previousSignals) signals.complete(Unit) }
             }
         }
 
-    override fun onRunningUseCasesChanged() {
-        _useCaseCamera?.runningUseCases?.run { updateTemplate() }
+    override fun onRunningUseCasesChanged(runningUseCases: Set) {
+        if (runningUseCases.isNotEmpty()) {
+            runningUseCases.updateTemplate()
+        }
+    }
+
+    private fun Deferred.propagateToAll(previousSignals: List>) {
+        for (previousSignal in previousSignals) {
+            propagateTo(previousSignal)
+        }
     }
 
     private val lock = Any()
@@ -165,7 +171,7 @@
                     parameters[CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE] = it
                 }
 
-                useCaseCamera?.requestControl?.addParametersAsync(values = parameters)
+                requestControl?.setParametersAsync(values = parameters)
             }
             ?.apply {
                 toCompletableDeferred().also { signal ->
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt
index d09a401..7ffef5d 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestControl.kt
@@ -48,12 +48,12 @@
 ) : UseCaseCameraControl {
     private val mutex = Mutex()
 
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
-            _useCaseCamera?.let { submitPendingRequests() }
+            _requestControl = value
+            _requestControl?.let { submitPendingRequests() }
         }
 
     public data class CaptureRequest(
@@ -98,8 +98,9 @@
 
         threads.sequentialScope.launch {
             val request = CaptureRequest(captureConfigs, captureMode, flashType, signal)
-            useCaseCamera?.let { camera ->
-                submitRequest(request, camera).propagateResultOrEnqueueRequest(request, camera)
+            requestControl?.let { requestControl ->
+                submitRequest(request, requestControl)
+                    .propagateResultOrEnqueueRequest(request, requestControl)
             }
                 ?: run {
                     // UseCaseCamera may become null by the time the coroutine is started
@@ -119,11 +120,11 @@
             mutex.withLock {
                 while (pendingRequests.isNotEmpty()) {
                     pendingRequests.poll()?.let { request ->
-                        useCaseCamera?.let { camera ->
-                            submitRequest(request, camera)
+                        requestControl?.let { requestControl ->
+                            submitRequest(request, requestControl)
                                 .propagateResultOrEnqueueRequest(
                                     submittedRequest = request,
-                                    requestCamera = camera
+                                    currentRequestControl = requestControl
                                 )
                         }
                     }
@@ -134,9 +135,9 @@
 
     private suspend fun submitRequest(
         request: CaptureRequest,
-        camera: UseCaseCamera
+        requestControl: UseCaseCameraRequestControl
     ): Deferred> {
-        debug { "StillCaptureRequestControl: submitting $request at $camera" }
+        debug { "StillCaptureRequestControl: submitting $request at $requestControl" }
         val flashMode = flashControl.flashMode
         // Prior to submitStillCaptures, wait until the pending flash mode session change is
         // completed. On some devices, AE preCapture triggered in submitStillCaptures may not
@@ -145,7 +146,7 @@
         flashControl.updateSignal.join()
         debug { "StillCaptureRequestControl: Issuing single capture" }
         val deferredList =
-            camera.requestControl.issueSingleCaptureAsync(
+            requestControl.issueSingleCaptureAsync(
                 request.captureConfigs,
                 request.captureMode,
                 request.flashType,
@@ -164,7 +165,7 @@
 
     private fun Deferred>.propagateResultOrEnqueueRequest(
         submittedRequest: CaptureRequest,
-        requestCamera: UseCaseCamera
+        currentRequestControl: UseCaseCameraRequestControl
     ) {
         invokeOnCompletion { cause: Throwable? ->
             if (
@@ -174,13 +175,13 @@
                 threads.sequentialScope.launch {
                     var isPending = true
 
-                    useCaseCamera?.let { latestCamera ->
-                        if (requestCamera != latestCamera) {
+                    requestControl?.let { latestRequestControl ->
+                        if (currentRequestControl != latestRequestControl) {
                             // camera has already been changed, can retry immediately
-                            submitRequest(submittedRequest, latestCamera)
+                            submitRequest(submittedRequest, latestRequestControl)
                                 .propagateResultOrEnqueueRequest(
                                     submittedRequest = submittedRequest,
-                                    requestCamera = latestCamera
+                                    currentRequestControl = latestRequestControl
                                 )
                             isPending = false
                         }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
index 2fc55ab3..7d2deb3 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/TorchControl.kt
@@ -44,11 +44,11 @@
     private val threads: UseCaseThreads,
 ) : UseCaseCameraControl {
 
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
             setTorchAsync(
                 torch =
                     when (torchStateLiveData.value) {
@@ -92,7 +92,7 @@
             return signal.createFailureResult(IllegalStateException("No flash unit"))
         }
 
-        useCaseCamera?.let { useCaseCamera ->
+        requestControl?.let { requestControl ->
             _torchState.setLiveDataValue(torch)
 
             threads.sequentialScope.launch {
@@ -108,7 +108,7 @@
                 _updateSignal = signal
 
                 // TODO(b/209757083), handle the failed result of the setTorchAsync().
-                useCaseCamera.requestControl.setTorchAsync(torch).join()
+                requestControl.setTorchAsync(torch).join()
 
                 // Hold the internal AE mode to ON while the torch is turned ON.
                 state3AControl.preferredAeMode =
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
index 6fbcac4..6b3020e 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCamera.kt
@@ -17,12 +17,10 @@
 package androidx.camera.camera2.pipe.integration.impl
 
 import android.hardware.camera2.CameraDevice
-import android.hardware.camera2.CaptureRequest
 import androidx.camera.camera2.pipe.CameraGraph
 import androidx.camera.camera2.pipe.GraphState.GraphStateError
 import androidx.camera.camera2.pipe.GraphState.GraphStateStarted
 import androidx.camera.camera2.pipe.GraphState.GraphStateStopped
-import androidx.camera.camera2.pipe.RequestTemplate
 import androidx.camera.camera2.pipe.core.Log.debug
 import androidx.camera.camera2.pipe.integration.adapter.RequestProcessorAdapter
 import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
@@ -30,7 +28,6 @@
 import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
 import androidx.camera.core.UseCase
 import androidx.camera.core.impl.Config
-import androidx.camera.core.impl.SessionConfig
 import androidx.camera.core.impl.SessionProcessorSurface
 import dagger.Binds
 import dagger.Module
@@ -38,7 +35,6 @@
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
@@ -49,31 +45,9 @@
 
 @JvmDefaultWithCompatibility
 public interface UseCaseCamera {
-    // UseCases
-    public var runningUseCases: Set
-
-    public var isPrimary: Boolean
-
-    public interface RunningUseCasesChangeListener {
-        /** Invoked when value of [UseCaseCamera.runningUseCases] has been changed. */
-        public fun onRunningUseCasesChanged()
-    }
-
     // RequestControl of the UseCaseCamera
     public val requestControl: UseCaseCameraRequestControl
 
-    // Parameters
-    public fun  setParameterAsync(
-        key: CaptureRequest.Key,
-        value: T,
-        priority: Config.OptionPriority = defaultOptionPriority,
-    ): Deferred
-
-    public fun setParametersAsync(
-        values: Map, Any>,
-        priority: Config.OptionPriority = defaultOptionPriority,
-    ): Deferred
-
     public fun setActiveResumeMode(enabled: Boolean) {}
 
     // Lifecycle
@@ -87,7 +61,6 @@
 public class UseCaseCameraImpl
 @Inject
 constructor(
-    private val controls: java.util.Set,
     private val useCaseGraphConfig: UseCaseGraphConfig,
     private val useCases: java.util.ArrayList,
     private val useCaseSurfaceManager: UseCaseSurfaceManager,
@@ -99,34 +72,6 @@
     private val debugId = useCaseCameraIds.incrementAndGet()
     private val closed = atomic(false)
 
-    override var runningUseCases: Set = setOf()
-        set(value) {
-            field = value
-
-            // Note: This may be called with the same set of values that was previously set. This
-            // is used as a signal to indicate the properties of the UseCase may have changed.
-            SessionConfigAdapter(value, isPrimary = isPrimary).getValidSessionConfigOrNull()?.let {
-                requestControl.setSessionConfigAsync(it)
-            }
-                ?: run {
-                    debug { "Unable to reset the session due to invalid config" }
-                    requestControl.setSessionConfigAsync(
-                        SessionConfig.Builder().apply { setTemplateType(defaultTemplate) }.build()
-                    )
-                }
-
-            controls.forEach { control ->
-                if (control is UseCaseCamera.RunningUseCasesChangeListener) {
-                    control.onRunningUseCasesChanged()
-                }
-            }
-        }
-
-    override var isPrimary: Boolean = true
-        set(value) {
-            field = value
-        }
-
     init {
         debug { "Configured $this for $useCases" }
         useCaseGraphConfig.apply { cameraStateAdapter.onGraphUpdated(graph) }
@@ -188,54 +133,10 @@
         }
     }
 
-    override fun  setParameterAsync(
-        key: CaptureRequest.Key,
-        value: T,
-        priority: Config.OptionPriority,
-    ): Deferred =
-        runIfNotClosed { setParametersAsync(mapOf(key to (value as Any)), priority) }
-            ?: canceledResult
-
-    override fun setParametersAsync(
-        values: Map, Any>,
-        priority: Config.OptionPriority,
-    ): Deferred =
-        runIfNotClosed {
-            requestControl.addParametersAsync(values = values, optionPriority = priority)
-        } ?: canceledResult
-
     override fun setActiveResumeMode(enabled: Boolean) {
         useCaseGraphConfig.graph.isForeground = enabled
     }
 
-    private fun UseCaseCameraRequestControl.setSessionConfigAsync(
-        sessionConfig: SessionConfig
-    ): Deferred =
-        runIfNotClosed {
-            setConfigAsync(
-                type = UseCaseCameraRequestControl.Type.SESSION_CONFIG,
-                config = sessionConfig.implementationOptions,
-                tags = sessionConfig.repeatingCaptureConfig.tagBundle.toMap(),
-                listeners =
-                    setOf(
-                        CameraCallbackMap.createFor(
-                            sessionConfig.repeatingCameraCaptureCallbacks,
-                            threads.backgroundExecutor
-                        )
-                    ),
-                template = RequestTemplate(sessionConfig.repeatingCaptureConfig.templateType),
-                streams =
-                    useCaseGraphConfig.getStreamIdsFromSurfaces(
-                        sessionConfig.repeatingCaptureConfig.surfaces
-                    ),
-                sessionConfig = sessionConfig,
-            )
-        } ?: canceledResult
-
-    private inline fun  runIfNotClosed(crossinline block: () -> R): R? {
-        return if (!closed.value) block() else null
-    }
-
     override fun toString(): String = "UseCaseCamera-$debugId"
 
     @Module
@@ -244,8 +145,4 @@
         @Binds
         public abstract fun provideUseCaseCamera(useCaseCamera: UseCaseCameraImpl): UseCaseCamera
     }
-
-    public companion object {
-        private val canceledResult = CompletableDeferred().apply { cancel() }
-    }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraControl.kt
index e08f92a..df794b5 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraControl.kt
@@ -17,7 +17,7 @@
 package androidx.camera.camera2.pipe.integration.impl
 
 public interface UseCaseCameraControl {
-    public var useCaseCamera: UseCaseCamera?
+    public var requestControl: UseCaseCameraRequestControl?
 
     public fun reset()
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
index 6aa775b..de128bc 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControl.kt
@@ -50,66 +50,64 @@
 internal const val DEFAULT_REQUEST_TEMPLATE = CameraDevice.TEMPLATE_PREVIEW
 
 /**
- * The RequestControl provides a couple of APIs to update the config of the camera, it also stores
- * the (repeating) request parameters of the configured [UseCaseCamera]. Once the parameters are
- * updated, it will trigger the update to the [UseCaseCameraState].
+ * Provides methods to update the configuration and parameters of the camera. It also stores the
+ * repeating request parameters associated with the configured [UseCaseCamera]. When parameters are
+ * updated, it triggers changes in the [UseCaseCameraState].
  *
- * The parameters can be stored for the different types of config respectively. Each type of the
- * config can be removed or overridden respectively without interfering with the other types.
+ * Parameters can be stored and managed according to different configuration types. Each type can be
+ * modified or overridden independently without affecting other types.
  */
 @JvmDefaultWithCompatibility
 public interface UseCaseCameraRequestControl {
-    /** The declaration order is the ordering to merge. */
+    /** Defines the types or categories of configuration parameters. */
     public enum class Type {
+        /** Parameters related to the overall session configuration. */
         SESSION_CONFIG,
+        /** General, default parameters. */
         DEFAULT,
-        CAMERA2_CAMERA_CONTROL,
+        /** Parameters specifically for interoperability with Camera2. */
+        CAMERA2_CAMERA_CONTROL
     }
 
-    // Repeating parameters
+    // Repeating Request Parameters
     /**
-     * Append a new option to update the repeating request.
+     * Asynchronously sets or updates parameters for the repeating capture request.
      *
-     * This method will: (1) Stores [values], [tags] and [listeners] by [type] respectively. The new
-     * inputs above will append to the values that store as the same [type], the existing values
-     * that don't conflict with the new inputs will not be cleared. If the [type] isn't set, it will
-     * treat the new inputs as the [Type.DEFAULT] (2) Update the repeating request by merging all
-     * the [values], [tags] and [listeners] from all the defined types.
+     * New values will overwrite any existing parameters with the same key for the given [type]. If
+     * no [type] is specified, it defaults to [Type.DEFAULT].
      *
-     * @param type the type of the input parameter, the possible value could be one of the [Type]
-     * @param values the new [CaptureRequest.Key] and value will be append to the repeating request
-     * @param optionPriority is the priority option that would be used to determine whether the new
-     *   value can override the existing value or not. This is default to
-     *   [Config.OptionPriority.OPTIONAL]
-     * @param tags the option tag that could be appended to the repeating request, its effect is
-     *   similar to the [CaptureRequest.Builder.setTag].
-     * @param listeners to receive the capture results.
+     * @param type The category of parameters being set (default: [Type.DEFAULT]).
+     * @param values A map of [CaptureRequest.Key] to their new values.
+     * @param optionPriority The priority for resolving conflicts if the same parameter is set
+     *   multiple times.
+     * @return A [Deferred] object representing the asynchronous operation.
      */
-    public fun addParametersAsync(
+    public fun setParametersAsync(
         type: Type = Type.DEFAULT,
         values: Map, Any> = emptyMap(),
         optionPriority: Config.OptionPriority = defaultOptionPriority,
-        tags: Map = emptyMap(),
-        listeners: Set = emptySet()
     ): Deferred
 
     /**
-     * Use a new [config] to update the repeating request.
+     * Asynchronously updates the repeating request with a new configuration.
      *
-     * This method will: (1) Stores [config], [tags] and [listeners] by [type] respectively. The new
-     * inputs above will take place of the existing value of the [type]. (2) Update the repeating
-     * request by merging all the [config], [tags] and [listeners] from all the defined types.
+     * This method replaces any existing configuration, tags, and listeners associated with the
+     * specified [type]. The repeating request is then rebuilt by merging all configurations, tags,
+     * and listeners from all defined types.
      *
-     * @param type the type of the input [config]
-     * @param config the new config values will be used to update the repeating request.
-     * @param tags the option tag that could be appended to the repeating request, its effect is
-     *   similar to the [CaptureRequest.Builder.setTag].
-     * @param streams Specify a list of streams that would be updated. Leave the value in empty will
-     *   use the [streams] that is previously specified. The update can only be processed after
-     *   specifying 1 or more valid streams.
-     * @param template The [RequestTemplate] will be used for the requests. Leave the value in empty
-     *   will use the [RequestTemplate] that is previously specified.
-     * @param listeners to receive the capture results.
+     * @param type The category of the configuration being updated (e.g., SESSION_CONFIG, DEFAULT).
+     * @param config The new configuration values to apply. If null, the existing configuration for
+     *   this type is cleared.
+     * @param tags Optional tags to append to the repeating request, similar to
+     *   [CaptureRequest.Builder.setTag].
+     * @param streams The specific streams to update. If empty, all previously specified streams are
+     *   updated. The update only proceeds if at least one valid stream is specified.
+     * @param template The [RequestTemplate] to use for the requests. If null, the previously
+     *   specified template is used.
+     * @param listeners Listeners to receive capture results.
+     * @param sessionConfig Optional [SessionConfig] to update if applicable to the configuration
+     *   type.
+     * @return A [Deferred] representing the asynchronous update operation.
      */
     public fun setConfigAsync(
         type: Type,
@@ -122,8 +120,29 @@
     ): Deferred
 
     // 3A
+    /**
+     * Asynchronously sets the torch (flashlight) state.
+     *
+     * @param enabled True to enable the torch, false to disable it.
+     * @return A [Deferred] representing the asynchronous operation and its result ([Result3A]).
+     */
     public suspend fun setTorchAsync(enabled: Boolean): Deferred
 
+    /**
+     * Asynchronously starts a 3A (Auto Exposure, Auto Focus, Auto White Balance) operation with the
+     * specified regions and locking behaviors.
+     *
+     * @param aeRegions The auto-exposure regions.
+     * @param afRegions The auto-focus regions.
+     * @param awbRegions The auto-white balance regions.
+     * @param aeLockBehavior The behavior for locking auto-exposure.
+     * @param afLockBehavior The behavior for locking auto-focus.
+     * @param awbLockBehavior The behavior for locking auto-white balance.
+     * @param afTriggerStartAeMode The AE mode to use when triggering AF.
+     * @param timeLimitNs The time limit for the 3A operation in nanoseconds. Defaults to
+     *   [CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS].
+     * @return A [Deferred] representing the asynchronous operation and its result ([Result3A]).
+     */
     public suspend fun startFocusAndMeteringAsync(
         aeRegions: List? = null,
         afRegions: List? = null,
@@ -135,9 +154,23 @@
         timeLimitNs: Long = CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS,
     ): Deferred
 
+    /**
+     * Asynchronously cancels any ongoing focus and metering operations.
+     *
+     * @return A [Deferred] representing the asynchronous operation and its result ([Result3A]).
+     */
     public suspend fun cancelFocusAndMeteringAsync(): Deferred
 
     // Capture
+    /**
+     * Asynchronously issues a single capture request.
+     *
+     * @param captureSequence A list of [CaptureConfig] objects defining the capture settings.
+     * @param captureMode The capture mode (from [ImageCapture.CaptureMode]).
+     * @param flashType The flash type (from [ImageCapture.FlashType]).
+     * @param flashMode The flash mode (from [ImageCapture.FlashMode]).
+     * @return A list of [Deferred] objects, one for each capture in the sequence.
+     */
     public suspend fun issueSingleCaptureAsync(
         captureSequence: List,
         @ImageCapture.CaptureMode captureMode: Int,
@@ -185,26 +218,18 @@
     private val infoBundleMap = mutableMapOf()
     private val lock = Any()
 
-    override fun addParametersAsync(
+    override fun setParametersAsync(
         type: UseCaseCameraRequestControl.Type,
         values: Map, Any>,
         optionPriority: Config.OptionPriority,
-        tags: Map,
-        listeners: Set
     ): Deferred =
         runIfNotClosed {
             synchronized(lock) {
                     debug { "[$type] Add request option: $values" }
                     infoBundleMap
                         .getOrPut(type) { InfoBundle() }
-                        .let {
-                            it.options.addAllCaptureRequestOptionsWithPriority(
-                                values,
-                                optionPriority
-                            )
-                            it.tags.putAll(tags)
-                            it.listeners.addAll(listeners)
-                        }
+                        .options
+                        .addAllCaptureRequestOptionsWithPriority(values, optionPriority)
                     infoBundleMap.merge()
                 }
                 .updateCameraStateAsync()
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
index d064344..54adf25 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManager.kt
@@ -74,10 +74,11 @@
 import androidx.camera.core.impl.stabilization.StabilizationMode
 import javax.inject.Inject
 import javax.inject.Provider
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.joinAll
 import kotlinx.coroutines.runBlocking
+import org.jetbrains.annotations.TestOnly
 
 /**
  * This class keeps track of the currently attached and active [UseCase]'s for a specific camera. A
@@ -354,13 +355,57 @@
             shouldAddRepeatingUseCase(runningUseCases) -> addRepeatingUseCase()
             shouldRemoveRepeatingUseCase(runningUseCases) -> removeRepeatingUseCase()
             else -> {
-                camera?.isPrimary = isPrimary
-                camera?.runningUseCases = runningUseCases
+                camera?.let {
+                    it.updateRepeatingRequests(isPrimary, runningUseCases)
+                    for (control in allControls) {
+                        if (control is RunningUseCasesChangeListener) {
+                            control.onRunningUseCasesChanged(runningUseCases)
+                        }
+                    }
+                }
             }
         }
     }
 
-    @OptIn(ExperimentalCoroutinesApi::class)
+    private fun UseCaseCamera.updateRepeatingRequests(
+        isPrimary: Boolean,
+        runningUseCases: Set
+    ) {
+        // Note: This may be called with the same set of values that was previously set. This
+        // is used as a signal to indicate the properties of the UseCase may have changed.
+        SessionConfigAdapter(runningUseCases, isPrimary = isPrimary)
+            .getValidSessionConfigOrNull()
+            ?.let { requestControl.setSessionConfigAsync(it) }
+            ?: run {
+                Log.debug { "Unable to reset the session due to invalid config" }
+                requestControl.setSessionConfigAsync(
+                    SessionConfig.Builder().apply { setTemplateType(defaultTemplate) }.build()
+                )
+            }
+    }
+
+    private fun UseCaseCameraRequestControl.setSessionConfigAsync(
+        sessionConfig: SessionConfig
+    ): Deferred =
+        setConfigAsync(
+            type = UseCaseCameraRequestControl.Type.SESSION_CONFIG,
+            config = sessionConfig.implementationOptions,
+            tags = sessionConfig.repeatingCaptureConfig.tagBundle.toMap(),
+            listeners =
+                setOf(
+                    CameraCallbackMap.createFor(
+                        sessionConfig.repeatingCameraCaptureCallbacks,
+                        useCaseThreads.get().backgroundExecutor
+                    )
+                ),
+            template = RequestTemplate(sessionConfig.repeatingCaptureConfig.templateType),
+            streams =
+                useCaseGraphConfig?.getStreamIdsFromSurfaces(
+                    sessionConfig.repeatingCaptureConfig.surfaces
+                ),
+            sessionConfig = sessionConfig,
+        )
+
     @GuardedBy("lock")
     private fun refreshAttachedUseCases(newUseCases: Set) {
         val useCases = newUseCases.toList()
@@ -392,7 +437,7 @@
         // Update list of active useCases
         if (useCases.isEmpty()) {
             for (control in allControls) {
-                control.useCaseCamera = null
+                control.requestControl = null
                 control.reset()
             }
             return
@@ -406,7 +451,7 @@
             //    resume UseCaseManager successfully
             // - And/or, the UseCaseManager is ready to be resumed under concurrent camera settings.
             for (control in allControls) {
-                control.useCaseCamera = null
+                control.requestControl = null
             }
         }
 
@@ -503,7 +548,7 @@
                     .build()
 
             for (control in allControls) {
-                control.useCaseCamera = camera
+                control.requestControl = camera?.requestControl
             }
 
             camera?.setActiveResumeMode(activeResumeEnabled)
@@ -523,6 +568,13 @@
         return attachedUseCases.intersect(activeUseCases)
     }
 
+    @TestOnly
+    @VisibleForTesting
+    public fun getRunningUseCasesForTest(): Set =
+        synchronized(lock) {
+            return getRunningUseCases()
+        }
+
     /**
      * Adds or removes repeating use case if needed.
      *
@@ -689,6 +741,25 @@
         cameraControl.setZslDisabledByUserCaseConfig(disableZsl)
     }
 
+    /**
+     * This interface defines a listener that is notified when the set of running UseCases changes.
+     *
+     * A "running" UseCase is one that is both attached and active, meaning it's bound to the
+     * lifecycle and ready to receive camera frames.
+     *
+     * Classes implementing this interface can take action when the active UseCase configuration
+     * changes.
+     */
+    public interface RunningUseCasesChangeListener {
+
+        /**
+         * Invoked when the set of running UseCases has been modified (added, removed, or updated).
+         *
+         * @param runningUseCases The updated set of UseCases that are currently running.
+         */
+        public fun onRunningUseCasesChanged(runningUseCases: Set)
+    }
+
     public companion object {
         internal data class UseCaseManagerConfig(
             val useCases: List,
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
index 4d4ad3a..2437ab8 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/ZoomControl.kt
@@ -78,11 +78,11 @@
             maxZoomRatio = maxZoomRatio
         )
 
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        get() = _useCaseCamera
+    private var _requestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        get() = _requestControl
         set(value) {
-            _useCaseCamera = value
+            _requestControl = value
             applyZoomState(_zoomState.value ?: defaultZoomState, false)
         }
 
@@ -157,7 +157,7 @@
         threads.sequentialScope.launch(start = CoroutineStart.UNDISPATCHED) {
             setZoomState(zoomState)
 
-            useCaseCamera?.let {
+            _requestControl?.let {
                 zoomCompat.applyAsync(zoomState.zoomRatio, it).propagateTo(signal)
             }
                 ?: signal.completeExceptionally(
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
index 4a53c52..63da8d3 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControl.kt
@@ -22,8 +22,8 @@
 import androidx.camera.camera2.pipe.integration.adapter.asListenableFuture
 import androidx.camera.camera2.pipe.integration.compat.Camera2CameraControlCompat
 import androidx.camera.camera2.pipe.integration.impl.ComboRequestListener
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraControl
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
 import androidx.camera.core.CameraControl
 import androidx.camera.core.impl.CameraControlInternal
@@ -49,16 +49,16 @@
 private constructor(
     private val compat: Camera2CameraControlCompat,
     private val threads: UseCaseThreads,
-    @VisibleForTesting internal val requestListener: ComboRequestListener,
+    @get:VisibleForTesting internal val requestListener: ComboRequestListener,
 ) : UseCaseCameraControl {
 
-    private var _useCaseCamera: UseCaseCamera? = null
-    override var useCaseCamera: UseCaseCamera?
-        @RestrictTo(RestrictTo.Scope.LIBRARY) get() = _useCaseCamera
+    private var _useCaseCameraRequestControl: UseCaseCameraRequestControl? = null
+    override var requestControl: UseCaseCameraRequestControl?
+        @RestrictTo(RestrictTo.Scope.LIBRARY) get() = _useCaseCameraRequestControl
         @RestrictTo(RestrictTo.Scope.LIBRARY)
         set(value) {
-            _useCaseCamera = value
-            _useCaseCamera?.also {
+            _useCaseCameraRequestControl = value
+            _useCaseCameraRequestControl?.also {
                 requestListener.removeListener(compat)
                 requestListener.addListener(compat, threads.sequentialExecutor)
                 compat.applyAsync(it, false)
@@ -147,7 +147,7 @@
     private fun updateAsync(tag: String): ListenableFuture =
         Futures.nonCancellationPropagating(
             threads.sequentialScope
-                .async { compat.applyAsync(useCaseCamera).await() }
+                .async { compat.applyAsync(requestControl).await() }
                 .asListenableFuture(tag)
         )
 
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
index af16f8f..355bea9 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapterTest.kt
@@ -37,7 +37,7 @@
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.createCameraInfoAdapter
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraInfoAdapterCreator.useCaseThreads
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
+import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.testing.FakeZoomCompat
 import androidx.camera.camera2.pipe.testing.FakeCameraDevices
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
@@ -167,7 +167,7 @@
         cameraInfoAdapter.zoomState.observeForever { currentZoomState = it }
 
         // if useCaseCamera is null, zoom setting operation will be cancelled
-        zoomControl.useCaseCamera = FakeUseCaseCamera()
+        zoomControl.requestControl = FakeUseCaseCameraRequestControl()
 
         val expectedZoomState = ZoomValue(3.0f, 1.0f, 10.0f)
         zoomControl.applyZoomState(expectedZoomState)[3, TimeUnit.SECONDS]
@@ -183,7 +183,7 @@
         cameraInfoAdapter.zoomState.observeForever { currentZoomState = it }
 
         // if useCaseCamera is null, zoom setting operation will be cancelled
-        zoomControl.useCaseCamera = FakeUseCaseCamera()
+        zoomControl.requestControl = FakeUseCaseCameraRequestControl()
 
         zoomControl.reset()
 
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
index fce6cf6..60a1e30 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/FocusMeteringControlTest.kt
@@ -40,7 +40,6 @@
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.camera2.pipe.integration.impl.FocusMeteringControl
 import androidx.camera.camera2.pipe.integration.impl.State3AControl
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
@@ -73,10 +72,8 @@
 import java.util.concurrent.Executors
 import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.async
 import kotlinx.coroutines.cancel
@@ -158,6 +155,7 @@
     private val cameraPropertiesMap = mutableMapOf()
 
     private val fakeRequestControl = FakeUseCaseCameraRequestControl(testScope)
+    private val runningUseCases = mutableSetOf()
 
     @Before
     fun setUp() {
@@ -171,9 +169,9 @@
     fun tearDown() {
         // CoroutineScope#cancel can throw exception if the scope has no job left
         try {
-            fakeUseCaseCamera.runningUseCases.forEach {
-                it.onStateDetached()
-                it.onUnbind()
+            for (useCase in runningUseCases) {
+                useCase.onStateDetached()
+                useCase.onUnbind()
             }
             // fakeUseCaseThreads may still be using Main dispatcher which sometimes
             // causes Dispatchers.resetMain() to throw an exception:
@@ -666,8 +664,7 @@
                 CAMERA_ID_0,
                 useCases = setOf(createPreview(Size(1920, 1080))),
             )
-        fakeUseCaseCamera.runningUseCases = emptySet()
-        focusMeteringControl.onRunningUseCasesChanged()
+        focusMeteringControl.onRunningUseCasesChanged(emptySet())
 
         startFocusMeteringAndAwait(FocusMeteringAction.Builder(point1).build())
 
@@ -1545,46 +1542,15 @@
         focusMeteringResultCallback.await()
     }
 
-    private val fakeUseCaseCamera =
-        object : UseCaseCamera {
-            override var runningUseCases = setOf()
-
-            override val requestControl: UseCaseCameraRequestControl
-                get() = fakeRequestControl
-
-            override var isPrimary: Boolean = true
-                set(value) {
-                    field = value
-                }
-
-            override fun  setParameterAsync(
-                key: CaptureRequest.Key,
-                value: T,
-                priority: androidx.camera.core.impl.Config.OptionPriority
-            ): Deferred {
-                TODO("Not yet implemented")
-            }
-
-            override fun setParametersAsync(
-                values: Map, Any>,
-                priority: androidx.camera.core.impl.Config.OptionPriority
-            ): Deferred {
-                TODO("Not yet implemented")
-            }
-
-            override fun close(): Job {
-                TODO("Not yet implemented")
-            }
-        }
-
     private fun initFocusMeteringControl(
         cameraId: String,
         useCases: Set = emptySet(),
         useCaseThreads: UseCaseThreads = fakeUseCaseThreads,
         state3AControl: State3AControl = createState3AControl(cameraId),
         zoomCompat: ZoomCompat = FakeZoomCompat()
-    ) =
-        FocusMeteringControl(
+    ): FocusMeteringControl {
+        runningUseCases.addAll(useCases)
+        return FocusMeteringControl(
                 cameraPropertiesMap[cameraId]!!,
                 MeteringRegionCorrection.Bindings.provideMeteringRegionCorrection(
                     CameraQuirks(
@@ -1603,10 +1569,10 @@
                 zoomCompat
             )
             .apply {
-                fakeUseCaseCamera.runningUseCases = useCases
-                useCaseCamera = fakeUseCaseCamera
-                onRunningUseCasesChanged()
+                requestControl = fakeRequestControl
+                onRunningUseCasesChanged(useCases)
             }
+    }
 
     private fun initCameraProperties(
         cameraIdStr: String,
@@ -1738,8 +1704,8 @@
     private fun createState3AControl(
         cameraId: String = CAMERA_ID_0,
         properties: CameraProperties = cameraPropertiesMap[cameraId]!!,
-        useCaseCamera: UseCaseCamera = fakeUseCaseCamera,
-    ) = FakeState3AControlCreator.createState3AControl(properties, useCaseCamera)
+        requestControl: UseCaseCameraRequestControl = fakeRequestControl,
+    ) = FakeState3AControlCreator.createState3AControl(properties, requestControl)
 
     private fun FocusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
         testScope: TestScope,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
index 92be8fb..5d25a6d 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SupportedSurfaceCombinationTest.kt
@@ -1655,16 +1655,34 @@
         }
     }
 
+    @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Test
+    fun checkUltraHdrCombinationsSupported_when8bit() {
+        // Device might support Ultra HDR but not 10-bit.
+        setupCamera(supportedFormats = intArrayOf(JPEG_R))
+        val supportedSurfaceCombination =
+            SupportedSurfaceCombination(context, fakeCameraMetadata, mockEncoderProfilesAdapter)
+
+        GuaranteedConfigurationsUtil.getUltraHdrSupportedCombinationList().forEach {
+            assertThat(
+                    supportedSurfaceCombination.checkSupported(
+                        SupportedSurfaceCombination.FeatureSettings(
+                            CameraMode.DEFAULT,
+                            requiredMaxBitDepth = DynamicRange.BIT_DEPTH_8_BIT,
+                            isUltraHdrOn = true
+                        ),
+                        it.surfaceConfigList
+                    )
+                )
+                .isTrue()
+        }
+    }
+
     /** JPEG_R/MAXIMUM when Ultra HDR is ON. */
     @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Test
     fun canSelectCorrectSizes_onlyJpegr_whenUltraHdrIsOn() {
-        val jpegUseCase =
-            createUseCase(
-                CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
-                imageFormat = JPEG_R
-            ) // JPEG
+        val jpegUseCase = createUseCase(CaptureType.IMAGE_CAPTURE, imageFormat = JPEG_R) // JPEG
         val useCaseExpectedResultMap =
             mutableMapOf().apply { put(jpegUseCase, maximumSize) }
         getSuggestedSpecsAndVerify(
@@ -1683,7 +1701,27 @@
         val jpegUseCase =
             createUseCase(
                 CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
+                imageFormat = JPEG_R,
+            ) // JPEG
+        val useCaseExpectedResultMap =
+            mutableMapOf().apply {
+                put(privUseCase, previewSize)
+                put(jpegUseCase, maximumSize)
+            }
+        getSuggestedSpecsAndVerify(
+            useCasesExpectedResultMap = useCaseExpectedResultMap,
+            supportedOutputFormats = intArrayOf(JPEG_R),
+        )
+    }
+
+    /** HLG10 PRIV/PREVIEW + JPEG_R/MAXIMUM when Ultra HDR is ON. */
+    @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Test
+    fun canSelectCorrectSizes_hlg10PrivPlusJpegr_whenUltraHdrIsOn() {
+        val privUseCase = createUseCase(CaptureType.PREVIEW, dynamicRange = HLG_10_BIT) // PRIV
+        val jpegUseCase =
+            createUseCase(
+                CaptureType.IMAGE_CAPTURE,
                 imageFormat = JPEG_R,
             ) // JPEG
         val useCaseExpectedResultMap =
@@ -1708,7 +1746,6 @@
         val jpegUseCase =
             createUseCase(
                 CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
                 imageFormat = JPEG_R,
             ) // JPEG
         val useCaseExpectedResultMap =
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
index e23b168..35fb7e0 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/CapturePipelineTest.kt
@@ -60,7 +60,6 @@
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraphSession
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.camera2.pipe.testing.FakeFrameInfo
@@ -309,8 +308,6 @@
 
     @Before
     fun setUp() {
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
-
         state3AControl =
             State3AControl(
                     fakeCameraProperties,
@@ -328,7 +325,7 @@
                         )
                     ),
                 )
-                .apply { useCaseCamera = fakeUseCaseCamera }
+                .apply { requestControl = fakeRequestControl }
 
         torchControl =
             TorchControl(
@@ -337,7 +334,7 @@
                     fakeUseCaseThreads,
                 )
                 .also {
-                    it.useCaseCamera = fakeUseCaseCamera
+                    it.requestControl = fakeRequestControl
 
                     // Ensure the control is updated after the UseCaseCamera been set.
                     assertThat(fakeRequestControl.setTorchSemaphore.tryAcquire(testScope)).isTrue()
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/EvCompControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/EvCompControlTest.kt
index 4567d6b..2e84d00 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/EvCompControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/EvCompControlTest.kt
@@ -27,7 +27,7 @@
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
 import androidx.camera.camera2.pipe.integration.compat.EvCompImpl
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
+import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.camera2.pipe.testing.FakeFrameInfo
 import androidx.camera.camera2.pipe.testing.FakeFrameMetadata
@@ -80,7 +80,7 @@
             EvCompControl(
                 EvCompImpl(FakeCameraProperties(metadata), fakeUseCaseThreads, comboRequestListener)
             )
-        exposureControl.useCaseCamera = FakeUseCaseCamera()
+        exposureControl.requestControl = FakeUseCaseCameraRequestControl()
     }
 
     @Test
@@ -112,7 +112,7 @@
         val deferred = exposureControl.updateAsync(1)
 
         // Act. Simulate control inactive by set useCaseCamera to null & call reset().
-        exposureControl.useCaseCamera = null
+        exposureControl.requestControl = null
         exposureControl.reset()
 
         // Assert. The exposure control has been set to inactive. It should throw an exception.
@@ -136,7 +136,7 @@
                 comboRequestListener
             )
         exposureControl = EvCompControl(evCompCompat)
-        exposureControl.useCaseCamera = FakeUseCaseCamera()
+        exposureControl.requestControl = FakeUseCaseCameraRequestControl()
 
         // Act.
         val deferred = exposureControl.updateAsync(1)
@@ -151,7 +151,7 @@
         val deferred = exposureControl.updateAsync(targetEv)
 
         // Act. Simulate the UseCaseCamera is recreated.
-        exposureControl.useCaseCamera = FakeUseCaseCamera()
+        exposureControl.requestControl = FakeUseCaseCameraRequestControl()
         comboRequestListener.simulateAeConverge(exposureValue = targetEv)
 
         // Assert. The setEV task should be completed.
@@ -164,7 +164,7 @@
         val deferred = exposureControl.updateAsync(1)
 
         // Act. Simulate the UseCaseCamera is recreated,
-        exposureControl.useCaseCamera = FakeUseCaseCamera()
+        exposureControl.requestControl = FakeUseCaseCameraRequestControl()
         // Act. Submits a new EV value.
         val deferred2 = exposureControl.updateAsync(targetEv)
         comboRequestListener.simulateAeConverge(exposureValue = targetEv)
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
index 61efe36..ba24b3c 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/FlashControlTest.kt
@@ -29,7 +29,6 @@
 import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.compat.workaround.UseFlashModeTorchFor3aUpdateImpl
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.core.CameraControl
@@ -82,7 +81,6 @@
         )
     }
     private val fakeRequestControl = FakeUseCaseCameraRequestControl()
-    private val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
     private val aeFpsRange =
         AeFpsRange(
             CameraQuirks(
@@ -139,11 +137,11 @@
                     NoOpAutoFlashAEModeDisabler,
                     aeFpsRange,
                 )
-                .apply { useCaseCamera = fakeUseCaseCamera }
+                .apply { requestControl = fakeRequestControl }
 
         torchControl =
             TorchControl(cameraProperties, state3AControl, fakeUseCaseThreads).apply {
-                useCaseCamera = fakeUseCaseCamera
+                requestControl = fakeRequestControl
             }
 
         flashControl =
@@ -159,13 +157,12 @@
                         NotUseFlashModeTorchFor3aUpdate
                     },
             )
-        flashControl.useCaseCamera = fakeUseCaseCamera
+        flashControl.requestControl = fakeRequestControl
         flashControl.setScreenFlash(screenFlash)
     }
 
     @Test
     fun setFlash_whenInactive(): Unit = runBlocking {
-        val fakeUseCaseCamera = FakeUseCaseCamera()
         val fakeCameraProperties = FakeCameraProperties()
 
         val flashControl =
@@ -176,7 +173,7 @@
                         NoOpAutoFlashAEModeDisabler,
                         aeFpsRange,
                     )
-                    .apply { useCaseCamera = fakeUseCaseCamera },
+                    .apply { requestControl = fakeRequestControl },
                 fakeUseCaseThreads,
                 TorchControl(fakeCameraProperties, state3AControl, fakeUseCaseThreads),
                 NotUseFlashModeTorchFor3aUpdate
@@ -267,7 +264,7 @@
         // Act. call reset & clear the UseCaseCamera.
         flashControl.setFlashAsync(ImageCapture.FLASH_MODE_ON)
         flashControl.reset()
-        flashControl.useCaseCamera = null
+        flashControl.requestControl = null
 
         assertThrows { deferred.awaitWithTimeout() }
     }
@@ -280,11 +277,10 @@
         val deferred = flashControl.setFlashAsync(ImageCapture.FLASH_MODE_ON)
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply { addParameterResult = CompletableDeferred() }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         // Act. Simulate the UseCaseCamera is recreated.
-        flashControl.useCaseCamera = fakeUseCaseCamera
-        state3AControl.useCaseCamera = fakeUseCaseCamera
+        flashControl.requestControl = fakeRequestControl
+        state3AControl.requestControl = fakeRequestControl
 
         // Simulate setFlash is completed on the recreated UseCaseCamera
         fakeRequestControl.addParameterResult.complete(Unit)
@@ -301,11 +297,10 @@
         val deferred = flashControl.setFlashAsync(ImageCapture.FLASH_MODE_ON)
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply { addParameterResult = CompletableDeferred() }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         // Act. Simulate the UseCaseCamera is recreated.
-        flashControl.useCaseCamera = fakeUseCaseCamera
-        state3AControl.useCaseCamera = fakeUseCaseCamera
+        flashControl.requestControl = fakeRequestControl
+        state3AControl.requestControl = fakeRequestControl
         // Act. Submits a new Flash mode.
         val deferred2 = flashControl.setFlashAsync(ImageCapture.FLASH_MODE_AUTO)
         // Simulate setFlash is completed on the recreated UseCaseCamera
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt
index eb3c8e5..a62aef8 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/StillCaptureRequestTest.kt
@@ -32,7 +32,7 @@
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
 import androidx.camera.camera2.pipe.integration.testing.FakeState3AControlCreator
 import androidx.camera.camera2.pipe.integration.testing.FakeSurface
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
+import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeFrameInfo
 import androidx.camera.camera2.pipe.testing.FakeRequestFailure
 import androidx.camera.camera2.pipe.testing.FakeRequestMetadata
@@ -83,26 +83,23 @@
     private lateinit var fakeUseCaseCameraState: UseCaseCameraState
 
     private val fakeState3AControl: State3AControl =
-        FakeState3AControlCreator.createState3AControl(useCaseCamera = FakeUseCaseCamera())
-
-    private lateinit var requestControl: UseCaseCameraRequestControl
-
-    private lateinit var fakeUseCaseCamera: UseCaseCamera
-
-    private val torchControl =
-        TorchControl(fakeCameraProperties, fakeState3AControl, fakeUseCaseThreads)
-
-    private val flashControl =
-        FlashControl(
-            fakeCameraProperties,
-            fakeState3AControl,
-            fakeUseCaseThreads,
-            torchControl,
-            NotUseFlashModeTorchFor3aUpdate,
+        FakeState3AControlCreator.createState3AControl(
+            requestControl = FakeUseCaseCameraRequestControl()
         )
 
+    private lateinit var useCaseCameraRequestControl: UseCaseCameraRequestControl
+
     private val stillCaptureRequestControl =
-        StillCaptureRequestControl(flashControl, fakeUseCaseThreads)
+        StillCaptureRequestControl(
+            FlashControl(
+                fakeCameraProperties,
+                fakeState3AControl,
+                fakeUseCaseThreads,
+                TorchControl(fakeCameraProperties, fakeState3AControl, fakeUseCaseThreads),
+                NotUseFlashModeTorchFor3aUpdate,
+            ),
+            fakeUseCaseThreads
+        )
 
     private val captureConfigList =
         listOf(
@@ -112,7 +109,7 @@
 
     @Before
     fun setUp() {
-        stillCaptureRequestControl.setNewUseCaseCamera()
+        stillCaptureRequestControl.setNewRequestControl()
     }
 
     @After
@@ -133,7 +130,7 @@
     @Test
     fun captureRequestsNotSubmitted_whenCameraIsNull() =
         runTest(testDispatcher) {
-            stillCaptureRequestControl.useCaseCamera = null
+            stillCaptureRequestControl.requestControl = null
 
             stillCaptureRequestControl.issueCaptureRequests()
 
@@ -144,13 +141,13 @@
     @Test
     fun captureRequestsSubmittedAfterCameraIsAvailable_whenCameraIsNull() =
         runTest(testDispatcher) {
-            stillCaptureRequestControl.useCaseCamera = null
+            stillCaptureRequestControl.requestControl = null
 
             stillCaptureRequestControl.issueCaptureRequests()
             advanceUntilIdle()
 
             // new camera is attached
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // the previous request should be submitted in the new camera
             advanceUntilIdle()
@@ -241,7 +238,7 @@
             }
 
             // new camera is attached
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // the previous request should be submitted again in the new camera
             advanceUntilIdle()
@@ -282,7 +279,7 @@
             // making sure issuing is attempted before new camera is not attached
             advanceUntilIdle()
 
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // the previous request should be submitted in the new camera
             advanceUntilIdle()
@@ -297,7 +294,7 @@
             advanceUntilIdle()
 
             // simulates previous camera closing and new camera being set
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             advanceUntilIdle()
             assertThat(fakeCameraGraphSession.submittedRequests.size).isEqualTo(0)
@@ -317,13 +314,13 @@
             }
 
             // new camera is attached
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // the previous request should be submitted again in the new camera
             advanceUntilIdle()
 
             // new camera is attached again
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // since the previous request was successful, it should not be submitted again
             assertThat(fakeCameraGraphSession.submittedRequests.size).isEqualTo(0)
@@ -333,7 +330,7 @@
     fun noPendingRequestRemaining_whenReset() =
         runTest(testDispatcher) {
             // simulate adding to pending list
-            stillCaptureRequestControl.useCaseCamera = null
+            stillCaptureRequestControl.requestControl = null
             stillCaptureRequestControl.issueCaptureRequests()
             stillCaptureRequestControl.issueCaptureRequests()
 
@@ -342,7 +339,7 @@
             stillCaptureRequestControl.reset()
 
             // new camera is attached
-            stillCaptureRequestControl.setNewUseCaseCamera()
+            stillCaptureRequestControl.setNewRequestControl()
 
             // if no new request submitted, it should imply all pending requests were cleared
             advanceUntilIdle()
@@ -353,7 +350,7 @@
     fun allPendingRequestsAreCancelled_whenReset() =
         runTest(testDispatcher) {
             // simulate adding to pending list
-            stillCaptureRequestControl.useCaseCamera = null
+            stillCaptureRequestControl.requestControl = null
             val requestFutures =
                 listOf(
                     stillCaptureRequestControl.issueCaptureRequests(),
@@ -426,7 +423,7 @@
             )
         val torchControl =
             TorchControl(fakeCameraProperties, fakeState3AControl, fakeUseCaseThreads)
-        requestControl =
+        useCaseCameraRequestControl =
             UseCaseCameraRequestControlImpl(
                 capturePipeline =
                     CapturePipelineImpl(
@@ -451,14 +448,10 @@
                 state = fakeUseCaseCameraState,
                 useCaseGraphConfig = fakeUseCaseGraphConfig,
             )
-        fakeUseCaseCamera =
-            FakeUseCaseCamera(
-                requestControl = requestControl,
-            )
     }
 
-    private fun StillCaptureRequestControl.setNewUseCaseCamera() {
+    private fun StillCaptureRequestControl.setNewRequestControl() {
         initUseCaseCameraScopeObjects()
-        useCaseCamera = fakeUseCaseCamera
+        requestControl = useCaseCameraRequestControl
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
index 9e21126..1c201dad 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/TorchControlTest.kt
@@ -26,7 +26,6 @@
 import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpAutoFlashAEModeDisabler
 import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.core.CameraControl
@@ -101,7 +100,7 @@
 
     @Before
     fun setUp() {
-        val fakeUseCaseCamera = FakeUseCaseCamera()
+        val fakeUseCaseCameraRequestControl = FakeUseCaseCameraRequestControl()
         val fakeCameraProperties = FakeCameraProperties(metadata)
         torchControl =
             TorchControl(
@@ -111,16 +110,16 @@
                         NoOpAutoFlashAEModeDisabler,
                         aeFpsRange,
                     )
-                    .apply { useCaseCamera = fakeUseCaseCamera },
+                    .apply { requestControl = fakeUseCaseCameraRequestControl },
                 fakeUseCaseThreads,
             )
-        torchControl.useCaseCamera = fakeUseCaseCamera
+        torchControl.requestControl = fakeUseCaseCameraRequestControl
     }
 
     @Test
     fun enableTorch_whenNoFlashUnit(): Unit = runBlocking {
         assertThrows {
-            val fakeUseCaseCamera = FakeUseCaseCamera()
+            val fakeUseCaseCameraRequestControl = FakeUseCaseCameraRequestControl()
             val fakeCameraProperties = FakeCameraProperties()
 
             // Without a flash unit, this Job will complete immediately with a IllegalStateException
@@ -131,10 +130,10 @@
                             NoOpAutoFlashAEModeDisabler,
                             aeFpsRange,
                         )
-                        .apply { useCaseCamera = fakeUseCaseCamera },
+                        .apply { requestControl = fakeUseCaseCameraRequestControl },
                     fakeUseCaseThreads,
                 )
-                .also { it.useCaseCamera = fakeUseCaseCamera }
+                .also { it.requestControl = fakeUseCaseCameraRequestControl }
                 .setTorchAsync(true)
                 .await()
         }
@@ -142,7 +141,7 @@
 
     @Test
     fun getTorchState_whenNoFlashUnit() {
-        val fakeUseCaseCamera = FakeUseCaseCamera()
+        val fakeUseCaseCameraRequestControl = FakeUseCaseCameraRequestControl()
         val fakeCameraProperties = FakeCameraProperties()
 
         val torchState =
@@ -153,10 +152,10 @@
                             NoOpAutoFlashAEModeDisabler,
                             aeFpsRange,
                         )
-                        .apply { useCaseCamera = fakeUseCaseCamera },
+                        .apply { requestControl = fakeUseCaseCameraRequestControl },
                     fakeUseCaseThreads,
                 )
-                .also { it.useCaseCamera = fakeUseCaseCamera }
+                .also { it.requestControl = fakeUseCaseCameraRequestControl }
                 .torchStateLiveData
                 .value
 
@@ -166,7 +165,7 @@
     @Test
     fun enableTorch_whenInactive(): Unit = runBlocking {
         assertThrows {
-            val fakeUseCaseCamera = FakeUseCaseCamera()
+            val fakeUseCaseCameraRequestControl = FakeUseCaseCameraRequestControl()
             val fakeCameraProperties = FakeCameraProperties(metadata)
 
             TorchControl(
@@ -176,7 +175,7 @@
                             NoOpAutoFlashAEModeDisabler,
                             aeFpsRange,
                         )
-                        .apply { useCaseCamera = fakeUseCaseCamera },
+                        .apply { requestControl = fakeUseCaseCameraRequestControl },
                     fakeUseCaseThreads,
                 )
                 .setTorchAsync(true)
@@ -186,7 +185,7 @@
 
     @Test
     fun getTorchState_whenInactive() {
-        torchControl.useCaseCamera = null
+        torchControl.requestControl = null
         Truth.assertThat(torchControl.torchStateLiveData.value).isEqualTo(TorchState.OFF)
     }
 
@@ -199,7 +198,7 @@
 
     @Test
     fun enableTorch_torchStateOn_whenNoFlashUnit_butFlashUnitAvailabilityIsIgnored() = runBlocking {
-        val fakeUseCaseCamera = FakeUseCaseCamera()
+        val fakeUseCaseCameraRequestControl = FakeUseCaseCameraRequestControl()
         val fakeCameraProperties = FakeCameraProperties()
 
         val torchControl =
@@ -210,11 +209,11 @@
                             NoOpAutoFlashAEModeDisabler,
                             aeFpsRange,
                         )
-                        .apply { useCaseCamera = fakeUseCaseCamera },
+                        .apply { requestControl = fakeUseCaseCameraRequestControl },
                     fakeUseCaseThreads,
                 )
                 .also {
-                    it.useCaseCamera = fakeUseCaseCamera
+                    it.requestControl = fakeUseCaseCameraRequestControl
                     it.setTorchAsync(torch = true, ignoreFlashUnitAvailability = true)
                 }
 
@@ -247,10 +246,7 @@
     fun enableTorchTwice_cancelPreviousFuture(): Unit = runBlocking {
         val deferred =
             torchControl
-                .also {
-                    it.useCaseCamera =
-                        FakeUseCaseCamera(requestControl = neverCompleteTorchRequestControl)
-                }
+                .also { it.requestControl = neverCompleteTorchRequestControl }
                 .setTorchAsync(true)
 
         torchControl.setTorchAsync(true)
@@ -262,10 +258,7 @@
     fun setInActive_cancelPreviousFuture(): Unit = runBlocking {
         val deferred =
             torchControl
-                .also {
-                    it.useCaseCamera =
-                        FakeUseCaseCamera(requestControl = neverCompleteTorchRequestControl)
-                }
+                .also { it.requestControl = neverCompleteTorchRequestControl }
                 .setTorchAsync(true)
 
         // reset() will be called after all the UseCases are detached.
@@ -314,18 +307,16 @@
     @Test
     fun useCaseCameraUpdated_setTorchResultShouldPropagate(): Unit = runBlocking {
         // Arrange.
-        torchControl.useCaseCamera =
-            FakeUseCaseCamera(requestControl = neverCompleteTorchRequestControl)
+        torchControl.requestControl = neverCompleteTorchRequestControl
 
         val deferred = torchControl.setTorchAsync(true)
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply {
                 setTorchResult = CompletableDeferred()
             }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         // Act. Simulate the UseCaseCamera is recreated.
-        torchControl.useCaseCamera = fakeUseCaseCamera
+        torchControl.requestControl = fakeRequestControl
 
         // Simulate setTorch is completed in the recreated UseCaseCamera
         fakeRequestControl.setTorchResult.complete(Result3A(status = Result3A.Status.OK))
@@ -337,16 +328,14 @@
     @Test
     fun useCaseCameraUpdated_onlyCompleteLatestRequest(): Unit = runBlocking {
         // Arrange.
-        torchControl.useCaseCamera =
-            FakeUseCaseCamera(requestControl = neverCompleteTorchRequestControl)
+        torchControl.requestControl = neverCompleteTorchRequestControl
 
         val deferred = torchControl.setTorchAsync(true)
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply { setTorchResult = CompletableDeferred() }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         // Act. Simulate the UseCaseCamera is recreated.
-        torchControl.useCaseCamera = fakeUseCaseCamera
+        torchControl.requestControl = fakeRequestControl
         // Act. Set Torch mode again.
         val deferred2 = torchControl.setTorchAsync(false)
         // Simulate setTorch is completed in the recreated UseCaseCamera
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
index a619b15..a6f3eb7 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraRequestControlTest.kt
@@ -122,7 +122,7 @@
         // Act
         requestControl.setSessionConfigAsync(sessionConfigBuilder.build()).await()
         requestControl
-            .addParametersAsync(
+            .setParametersAsync(
                 values = mapOf(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION to 5)
             )
             .await()
@@ -188,7 +188,7 @@
             type = UseCaseCameraRequestControl.Type.CAMERA2_CAMERA_CONTROL,
             config = camera2CameraControlConfig
         )
-        requestControl.addParametersAsync(
+        requestControl.setParametersAsync(
             values = mapOf(CaptureRequest.CONTROL_AE_MODE to CaptureRequest.CONTROL_AE_MODE_OFF)
         )
         requestControl.setSessionConfigAsync(sessionConfigBuilder.build()).await()
@@ -210,9 +210,6 @@
         val testCamera2InteropTagKey = "testCamera2InteropTagKey"
         val testCamera2InteropTagValue = "testCamera2InteropTagValue"
 
-        val testTagKey = "testTagKey"
-        val testTagValue = "testTagValue"
-
         val sessionConfigBuilder =
             SessionConfig.Builder().also { sessionConfigBuilder ->
                 sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
@@ -232,10 +229,6 @@
                     .build(),
             tags = mapOf(testCamera2InteropTagKey to testCamera2InteropTagValue)
         )
-        requestControl.addParametersAsync(
-            values = mapOf(CaptureRequest.CONTROL_AE_MODE to CaptureRequest.CONTROL_AE_MODE_OFF),
-            tags = mapOf(testTagKey to testTagValue)
-        )
         requestControl.setSessionConfigAsync(sessionConfigBuilder.build()).await()
 
         // Assert.
@@ -244,14 +237,12 @@
         assertThat(tagBundle).isNotNull()
         assertThat(tagBundle.getTag(testSessionTagKey)).isEqualTo(testSessionTagValue)
         assertThat(tagBundle.getTag(testCamera2InteropTagKey)).isEqualTo(testCamera2InteropTagValue)
-        assertThat(tagBundle.getTag(testTagKey)).isEqualTo(testTagValue)
     }
 
     @Test
     fun testMergeListener(): Unit = runBlocking {
         // Arrange
         val testRequestListener = TestRequestListener()
-        val testRequestListener1 = TestRequestListener()
         val testCaptureCallback =
             object : CameraCaptureCallback() {
                 val latch = CountDownLatch(1)
@@ -282,10 +273,6 @@
                     .build(),
             listeners = setOf(testRequestListener)
         )
-        requestControl.addParametersAsync(
-            values = mapOf(CaptureRequest.CONTROL_AE_MODE to CaptureRequest.CONTROL_AE_MODE_OFF),
-            listeners = setOf(testRequestListener1)
-        )
         requestControl.setSessionConfigAsync(sessionConfigBuilder.build()).await()
 
         // Invoke the onComplete on all the listeners.
@@ -295,7 +282,6 @@
 
         // Assert. All the listeners should receive the onComplete signal.
         assertThat(testRequestListener.latch.await(1, TimeUnit.SECONDS)).isTrue()
-        assertThat(testRequestListener1.latch.await(1, TimeUnit.SECONDS)).isTrue()
         assertThat(testCaptureCallback.latch.await(1, TimeUnit.SECONDS)).isTrue()
     }
 
@@ -345,7 +331,7 @@
         // Act
         requestControl.setSessionConfigAsync(sessionConfigBuilder.build()).await()
         requestControl
-            .addParametersAsync(
+            .setParametersAsync(
                 values = mapOf(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION to 5)
             )
             .await()
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
deleted file mode 100644
index c900d84..0000000
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseCameraTest.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.camera.camera2.pipe.integration.impl
-
-import android.hardware.camera2.CameraDevice
-import android.os.Build
-import androidx.camera.camera2.pipe.CameraPipe
-import androidx.camera.camera2.pipe.StreamId
-import androidx.camera.camera2.pipe.integration.adapter.CameraStateAdapter
-import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
-import androidx.camera.camera2.pipe.integration.adapter.SessionConfigAdapter
-import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpInactiveSurfaceCloser
-import androidx.camera.camera2.pipe.integration.compat.workaround.NoOpTemplateParamsOverride
-import androidx.camera.camera2.pipe.integration.config.UseCaseGraphConfig
-import androidx.camera.camera2.pipe.integration.testing.FakeCameraGraph
-import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
-import androidx.camera.camera2.pipe.integration.testing.FakeCapturePipeline
-import androidx.camera.camera2.pipe.integration.testing.FakeSurface
-import androidx.camera.core.impl.DeferrableSurface
-import androidx.camera.core.impl.SessionConfig
-import androidx.camera.testing.impl.fakes.FakeUseCase
-import androidx.camera.testing.impl.fakes.FakeUseCaseConfig
-import androidx.test.core.app.ApplicationProvider
-import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.TimeUnit
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.asExecutor
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.annotation.Config
-import org.robolectric.annotation.internal.DoNotInstrument
-
-@RunWith(RobolectricCameraPipeTestRunner::class)
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
-@DoNotInstrument
-class UseCaseCameraTest {
-    private val surface = FakeSurface()
-    private val surfaceToStreamMap: Map = mapOf(surface to StreamId(0))
-    private val useCaseThreads by lazy {
-        val dispatcher = Dispatchers.Default
-        val cameraScope = CoroutineScope(Job() + dispatcher)
-
-        UseCaseThreads(cameraScope, dispatcher.asExecutor(), dispatcher)
-    }
-    private val fakeCameraProperties = FakeCameraProperties()
-    private val fakeCameraGraph = FakeCameraGraph()
-    private val fakeUseCaseGraphConfig =
-        UseCaseGraphConfig(
-            graph = fakeCameraGraph,
-            surfaceToStreamMap = surfaceToStreamMap,
-            cameraStateAdapter = CameraStateAdapter(),
-        )
-    private val fakeUseCaseCameraState =
-        UseCaseCameraState(
-            useCaseGraphConfig = fakeUseCaseGraphConfig,
-            threads = useCaseThreads,
-            sessionProcessorManager = null,
-            templateParamsOverride = NoOpTemplateParamsOverride,
-        )
-    private val requestControl =
-        UseCaseCameraRequestControlImpl(
-            capturePipeline = FakeCapturePipeline(),
-            state = fakeUseCaseCameraState,
-            useCaseGraphConfig = fakeUseCaseGraphConfig,
-        )
-
-    @After
-    fun tearDown() {
-        surface.close()
-    }
-
-    @Test
-    fun setInvalidSessionConfig_repeatingShouldStop() {
-        // Arrange
-        val fakeUseCase =
-            FakeTestUseCase().apply {
-                // Set a valid SessionConfig with Surface and template.
-                setupSessionConfig(
-                    SessionConfig.Builder().apply {
-                        setTemplateType(CameraDevice.TEMPLATE_PREVIEW)
-                        addSurface(surface)
-                    }
-                )
-            }
-
-        @Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
-        val useCaseCamera =
-            UseCaseCameraImpl(
-                    controls =
-                        emptySet() as java.util.Set,
-                    useCaseGraphConfig = fakeUseCaseGraphConfig,
-                    useCases = arrayListOf(fakeUseCase),
-                    useCaseSurfaceManager =
-                        UseCaseSurfaceManager(
-                            useCaseThreads,
-                            CameraPipe(
-                                CameraPipe.Config(ApplicationProvider.getApplicationContext())
-                            ),
-                            NoOpInactiveSurfaceCloser,
-                        ),
-                    threads = useCaseThreads,
-                    sessionProcessorManager = null,
-                    sessionConfigAdapter = SessionConfigAdapter(listOf(fakeUseCase)),
-                    requestControl = requestControl,
-                )
-                .also { it.runningUseCases = setOf(fakeUseCase) }
-        assumeTrue(
-            fakeCameraGraph.fakeCameraGraphSession.repeatingRequestSemaphore.tryAcquire(
-                1,
-                3,
-                TimeUnit.SECONDS
-            )
-        )
-
-        // Act. Set an invalid SessionConfig which doesn't have the template.
-        fakeUseCase.setupSessionConfig(SessionConfig.Builder().apply { addSurface(surface) })
-
-        useCaseCamera.runningUseCases = setOf(fakeUseCase)
-
-        // Assert. The stopRepeating() should be called.
-        assertThat(
-                fakeCameraGraph.fakeCameraGraphSession.stopRepeatingSemaphore.tryAcquire(
-                    1,
-                    3,
-                    TimeUnit.SECONDS
-                )
-            )
-            .isTrue()
-    }
-}
-
-private class FakeTestUseCase :
-    FakeUseCase(FakeUseCaseConfig.Builder().setTargetName("UseCase").useCaseConfig) {
-
-    fun setupSessionConfig(sessionConfigBuilder: SessionConfig.Builder) {
-        updateSessionConfig(listOf(sessionConfigBuilder.build()))
-        notifyActive()
-    }
-}
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
index 0e24668..82d453f 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/UseCaseManagerTest.kt
@@ -50,13 +50,13 @@
 import androidx.camera.camera2.pipe.integration.compat.workaround.TemplateParamsOverride
 import androidx.camera.camera2.pipe.integration.compat.workaround.TemplateParamsQuirkOverride
 import androidx.camera.camera2.pipe.integration.config.CameraConfig
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera.RunningUseCasesChangeListener
 import androidx.camera.camera2.pipe.integration.interop.Camera2CameraControl
 import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
 import androidx.camera.camera2.pipe.integration.testing.FakeCamera2CameraControlCompat
 import androidx.camera.camera2.pipe.integration.testing.FakeCameraProperties
 import androidx.camera.camera2.pipe.integration.testing.FakeSessionProcessor
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraComponentBuilder
+import androidx.camera.camera2.pipe.integration.testing.generateFakeStreamConfigurationMap
 import androidx.camera.camera2.pipe.testing.FakeCameraMetadata
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.ImageCapture
@@ -92,17 +92,15 @@
 import org.robolectric.shadow.api.Shadow
 import org.robolectric.shadows.ShadowCameraCharacteristics
 import org.robolectric.shadows.ShadowCameraManager
-import org.robolectric.shadows.StreamConfigurationMapBuilder
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(RobolectricCameraPipeTestRunner::class)
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 class UseCaseManagerTest {
     private val supportedSizes = arrayOf(Size(640, 480))
-    private val streamConfigurationMap =
-        StreamConfigurationMapBuilder.newBuilder()
-            .apply { supportedSizes.forEach(::addOutputSize) }
-            .build()
+    // If a device supports Ultra HDR, streamConfigurationMap.getOutputFormat() should contains
+    // JPEG_R format.
+    private val streamConfigurationMap = generateFakeStreamConfigurationMap(supportedSizes)
     private val useCaseManagerList = mutableListOf()
     private val useCaseList = mutableListOf()
     private lateinit var useCaseThreads: UseCaseThreads
@@ -124,7 +122,7 @@
         useCaseManager.attach(listOf(useCase))
 
         // Assert
-        val enabledUseCases = useCaseManager.camera?.runningUseCases
+        val enabledUseCases = useCaseManager.getRunningUseCasesForTest()
         assertThat(enabledUseCases).isEmpty()
     }
 
@@ -140,7 +138,7 @@
         useCaseManager.activate(useCase)
 
         // Assert
-        val enabledUseCases = useCaseManager.camera?.runningUseCases
+        val enabledUseCases = useCaseManager.getRunningUseCasesForTest()
         assertThat(enabledUseCases).containsExactly(useCase)
     }
 
@@ -163,7 +161,7 @@
 
         // Assert
         assertNotNull(useCaseManager.camera)
-        assertThat(useCaseManager.camera!!.runningUseCases)
+        assertThat(useCaseManager.getRunningUseCasesForTest())
             .containsExactly(previewUseCase, imageCaptureUseCase)
     }
 
@@ -206,7 +204,7 @@
         // Assert
         assertNotNull(useCaseManager.camera)
         // Check that the new set of running use cases is Preview, ImageCapture and ImageAnalysis.
-        assertThat(useCaseManager.camera!!.runningUseCases)
+        assertThat(useCaseManager.getRunningUseCasesForTest())
             .containsExactly(previewUseCase, imageCaptureUseCase, imageAnalysisUseCase)
     }
 
@@ -224,7 +222,7 @@
         useCaseManager.activate(imageCapture)
 
         // Assert
-        val enabledUseCases = useCaseManager.camera?.runningUseCases
+        val enabledUseCases = useCaseManager.getRunningUseCasesForTest()
         assertThat(enabledUseCases).containsExactly(preview, imageCapture)
     }
 
@@ -240,7 +238,8 @@
         useCaseManager.activate(imageCapture)
 
         // Assert
-        val enabledUseCaseClasses = useCaseManager.camera?.runningUseCases?.map { it::class.java }
+        val enabledUseCaseClasses =
+            useCaseManager.getRunningUseCasesForTest().map { it::class.java }
         assertThat(enabledUseCaseClasses)
             .containsExactly(ImageCapture::class.java, MeteringRepeating::class.java)
     }
@@ -260,7 +259,7 @@
         useCaseManager.activate(preview)
 
         // Assert
-        val activeUseCases = useCaseManager.camera?.runningUseCases
+        val activeUseCases = useCaseManager.getRunningUseCasesForTest()
         assertThat(activeUseCases).containsExactly(preview, imageCapture)
     }
 
@@ -279,7 +278,8 @@
         useCaseManager.detach(listOf(preview))
 
         // Assert
-        val enabledUseCaseClasses = useCaseManager.camera?.runningUseCases?.map { it::class.java }
+        val enabledUseCaseClasses =
+            useCaseManager.getRunningUseCasesForTest().map { it::class.java }
         assertThat(enabledUseCaseClasses)
             .containsExactly(ImageCapture::class.java, MeteringRepeating::class.java)
     }
@@ -319,7 +319,7 @@
         useCaseManager.deactivate(imageCapture)
 
         // Assert
-        val enabledUseCases = useCaseManager.camera?.runningUseCases
+        val enabledUseCases = useCaseManager.getRunningUseCasesForTest()
         assertThat(enabledUseCases).isEmpty()
     }
 
@@ -383,19 +383,18 @@
         // Arrange
         initializeUseCaseThreads(this)
         val fakeControl =
-            object : UseCaseCameraControl, RunningUseCasesChangeListener {
-                var runningUseCases: Set = emptySet()
+            object : UseCaseCameraControl, UseCaseManager.RunningUseCasesChangeListener {
+                var runningUseCaseSet: Set = emptySet()
 
-                @Suppress("UNUSED_PARAMETER")
-                override var useCaseCamera: UseCaseCamera?
+                override var requestControl: UseCaseCameraRequestControl?
                     get() = TODO("Not yet implemented")
-                    set(value) {
-                        runningUseCases = value?.runningUseCases ?: emptySet()
-                    }
+                    set(_) {}
 
                 override fun reset() {}
 
-                override fun onRunningUseCasesChanged() {}
+                override fun onRunningUseCasesChanged(runningUseCases: Set) {
+                    runningUseCaseSet = runningUseCases
+                }
             }
 
         val useCaseManager = createUseCaseManager(controls = setOf(fakeControl))
@@ -408,7 +407,7 @@
         useCaseManager.attach(listOf(preview, useCase))
 
         // Assert
-        assertThat(fakeControl.runningUseCases).isEqualTo(setOf(preview, useCase))
+        assertThat(fakeControl.runningUseCaseSet).isEqualTo(setOf(preview, useCase))
     }
 
     @Test
@@ -428,7 +427,7 @@
         advanceUntilIdle()
 
         assertNotNull(useCaseManager.camera)
-        assertThat(useCaseManager.camera!!.runningUseCases)
+        assertThat(useCaseManager.getRunningUseCasesForTest())
             .containsExactly(previewUseCase, imageCaptureUseCase)
         assertTrue(previewUseCase.cameraControlReady)
         assertTrue(imageCaptureUseCase.cameraControlReady)
@@ -477,7 +476,7 @@
         // Assert
         assertNotNull(useCaseManager.camera)
         // Check that the new set of running use cases is Preview, ImageCapture and ImageAnalysis.
-        assertThat(useCaseManager.camera!!.runningUseCases)
+        assertThat(useCaseManager.getRunningUseCasesForTest())
             .containsExactly(previewUseCase, imageCaptureUseCase, imageAnalysisUseCase)
         // Despite only attaching the ImageAnalysis use case in the prior step. All not-yet-notified
         // use cases should be notified that their camera controls are ready.
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/ZoomControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/ZoomControlTest.kt
index aa18499..bed7cf8 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/ZoomControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/impl/ZoomControlTest.kt
@@ -18,7 +18,7 @@
 
 import android.os.Build
 import androidx.camera.camera2.pipe.integration.adapter.RobolectricCameraPipeTestRunner
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
+import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.testing.FakeZoomCompat
 import androidx.camera.core.CameraControl
 import androidx.testutils.MainDispatcherRule
@@ -68,7 +68,7 @@
     fun setUp() {
         zoomControl =
             ZoomControl(fakeUseCaseThreads, zoomCompat).apply {
-                useCaseCamera = FakeUseCaseCamera()
+                requestControl = FakeUseCaseCameraRequestControl()
             }
     }
 
@@ -110,7 +110,7 @@
 
         // Act. Simulate the UseCaseCamera is recreated before applying zoom.
         zoomCompat.applyAsyncResult = CompletableDeferred() // incomplete deferred of new camera
-        zoomControl.useCaseCamera = FakeUseCaseCamera()
+        zoomControl.requestControl = FakeUseCaseCameraRequestControl()
         zoomCompat.applyAsyncResult.complete(Unit)
 
         // Assert. The setZoomRatio task should be completed.
@@ -144,7 +144,7 @@
         val result1 = zoomControl.setZoomRatio(3.0f)
 
         // Act. Simulate the UseCaseCamera is recreated,
-        zoomControl.useCaseCamera = FakeUseCaseCamera()
+        zoomControl.requestControl = FakeUseCaseCameraRequestControl()
         // Act. Submit a new zoom ratio.
         val result2 = zoomControl.setZoomRatio(2.0f)
         zoomCompat.applyAsyncResult.complete(Unit)
@@ -162,7 +162,7 @@
         zoomCompat.applyAsyncResult = CompletableDeferred() // incomplete deferred
         val result = zoomControl.setZoomRatio(3.0f)
 
-        zoomControl.useCaseCamera = null
+        zoomControl.requestControl = null
 
         assertFutureFailedWithOperationCancellation(result)
     }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControlTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControlTest.kt
index 009772e..371648c 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControlTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/interop/Camera2CameraControlTest.kt
@@ -28,7 +28,6 @@
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.impl.UseCaseThreads
 import androidx.camera.camera2.pipe.integration.impl.toParameters
-import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCamera
 import androidx.camera.camera2.pipe.integration.testing.FakeUseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.testing.FakeFrameInfo
 import androidx.camera.camera2.pipe.testing.FakeFrameMetadata
@@ -68,7 +67,6 @@
     }
     private val comboRequestListener = ComboRequestListener()
     private val fakeRequestControl = FakeUseCaseCameraRequestControl()
-    private val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
     private val camera2CameraControlCompatImpl = Camera2CameraControlCompatImpl()
     private lateinit var camera2CameraControl: Camera2CameraControl
 
@@ -80,7 +78,7 @@
                 threads = fakeUseCaseThreads,
                 requestListener = comboRequestListener,
             )
-        camera2CameraControl.useCaseCamera = fakeUseCaseCamera
+        camera2CameraControl.requestControl = fakeRequestControl
     }
 
     @Test
@@ -89,7 +87,6 @@
         val completeDeferred = CompletableDeferred()
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply { setConfigResult = completeDeferred }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         val resultFuture =
             camera2CameraControl.setCaptureRequestOptions(
@@ -102,7 +99,7 @@
             )
 
         // Act. Simulate the UseCaseCamera is recreated.
-        camera2CameraControl.useCaseCamera = fakeUseCaseCamera
+        camera2CameraControl.requestControl = fakeRequestControl
         // Simulate setRequestOption is completed in the recreated UseCaseCamera
         completeDeferred.complete(Unit)
         val requestsToCamera =
@@ -126,7 +123,6 @@
         val completeDeferred = CompletableDeferred()
         val fakeRequestControl =
             FakeUseCaseCameraRequestControl().apply { setConfigResult = completeDeferred }
-        val fakeUseCaseCamera = FakeUseCaseCamera(requestControl = fakeRequestControl)
 
         val resultFuture =
             camera2CameraControl.setCaptureRequestOptions(
@@ -139,7 +135,7 @@
             )
 
         // Act. Simulate the UseCaseCamera is recreated.
-        camera2CameraControl.useCaseCamera = fakeUseCaseCamera
+        camera2CameraControl.requestControl = fakeRequestControl
         // Act. Submit a new request option.
         val resultFuture2 =
             camera2CameraControl.setCaptureRequestOptions(
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
index e4f612e..04e14cd 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCamera2CameraControlCompat.kt
@@ -17,7 +17,7 @@
 package androidx.camera.camera2.pipe.integration.testing
 
 import androidx.camera.camera2.pipe.integration.compat.Camera2CameraControlCompat
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.camera2.pipe.integration.interop.CaptureRequestOptions
 import androidx.camera.camera2.pipe.integration.interop.ExperimentalCamera2Interop
 import kotlinx.coroutines.CompletableDeferred
@@ -41,7 +41,10 @@
         // No-op
     }
 
-    override fun applyAsync(camera: UseCaseCamera?, cancelPreviousTask: Boolean): Deferred {
+    override fun applyAsync(
+        requestControl: UseCaseCameraRequestControl?,
+        cancelPreviousTask: Boolean
+    ): Deferred {
         return CompletableDeferred(null).apply { complete(null) }
     }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
index 1d251df..1b53a80 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraInfoAdapterCreator.kt
@@ -113,7 +113,7 @@
                     mapOf(CameraBackendId(cameraId.value) to listOf(cameraProperties.metadata))
             )
     ): CameraInfoAdapter {
-        val fakeUseCaseCamera = FakeUseCaseCamera()
+        val fakeRequestControl = FakeUseCaseCameraRequestControl()
         val fakeStreamConfigurationMap =
             StreamConfigurationMapCompat(
                 streamConfigurationMap,
@@ -130,7 +130,7 @@
                     NoOpAutoFlashAEModeDisabler,
                     AeFpsRange(fakeCameraQuirks),
                 )
-                .apply { useCaseCamera = fakeUseCaseCamera }
+                .apply { requestControl = fakeRequestControl }
         return CameraInfoAdapter(
             cameraProperties,
             CameraConfig(cameraId),
@@ -150,7 +150,7 @@
                     useCaseThreads,
                     FakeZoomCompat(),
                 )
-                .apply { useCaseCamera = fakeUseCaseCamera },
+                .apply { requestControl = fakeRequestControl },
             fakeCameraQuirks,
             EncoderProfilesProviderAdapter(cameraId.value, fakeCameraQuirks.quirks),
             fakeStreamConfigurationMap,
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
index 2e685e3..a82319a 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeEvCompCompat.kt
@@ -19,7 +19,7 @@
 import android.util.Range
 import android.util.Rational
 import androidx.camera.camera2.pipe.integration.compat.EvCompCompat
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import kotlinx.coroutines.Deferred
 
 class FakeEvCompCompat
@@ -34,7 +34,7 @@
 
     override fun applyAsync(
         evCompIndex: Int,
-        camera: UseCaseCamera,
+        requestControl: UseCaseCameraRequestControl,
         cancelPreviousTask: Boolean,
     ): Deferred {
         TODO("Not yet implemented")
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt
index 9b3dbe0..65ce9f4 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeState3AControlCreator.kt
@@ -23,13 +23,13 @@
 import androidx.camera.camera2.pipe.integration.compat.workaround.OutputSizesCorrector
 import androidx.camera.camera2.pipe.integration.impl.CameraProperties
 import androidx.camera.camera2.pipe.integration.impl.State3AControl
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import org.robolectric.shadows.StreamConfigurationMapBuilder
 
 object FakeState3AControlCreator {
     fun createState3AControl(
         properties: CameraProperties = FakeCameraProperties(),
-        useCaseCamera: UseCaseCamera = FakeUseCaseCamera(),
+        requestControl: UseCaseCameraRequestControl = FakeUseCaseCameraRequestControl(),
     ) =
         State3AControl(
                 properties,
@@ -47,5 +47,5 @@
                     )
                 ),
             )
-            .apply { this.useCaseCamera = useCaseCamera }
+            .apply { this.requestControl = requestControl }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
index 312045f..9da279b 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeUseCaseCamera.kt
@@ -34,7 +34,6 @@
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
 import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import androidx.camera.core.ImageCapture
-import androidx.camera.core.UseCase
 import androidx.camera.core.impl.CaptureConfig
 import androidx.camera.core.impl.Config
 import androidx.camera.core.impl.DeferrableSurface
@@ -72,12 +71,12 @@
 
     override fun build(): UseCaseCameraComponent {
         buildInvocationCount++
-        return FakeUseCaseCameraComponent(config.provideUseCaseList())
+        return FakeUseCaseCameraComponent()
     }
 }
 
-class FakeUseCaseCameraComponent(useCases: List) : UseCaseCameraComponent {
-    private val fakeUseCaseCamera = FakeUseCaseCamera(useCases.toSet())
+class FakeUseCaseCameraComponent() : UseCaseCameraComponent {
+    private val fakeUseCaseCamera = FakeUseCaseCamera()
     private val cameraGraph = FakeCameraGraph()
     private val cameraStateAdapter = CameraStateAdapter()
 
@@ -102,12 +101,10 @@
     var setConfigResult = CompletableDeferred(Unit)
     var setTorchResult = CompletableDeferred(Result3A(status = Result3A.Status.OK))
 
-    override fun addParametersAsync(
+    override fun setParametersAsync(
         type: UseCaseCameraRequestControl.Type,
         values: Map, Any>,
         optionPriority: Config.OptionPriority,
-        tags: Map,
-        listeners: Set
     ): Deferred {
         addParameterCalls.add(values)
         return addParameterResult
@@ -233,30 +230,9 @@
 
 // TODO: Further implement the methods in this class as needed
 class FakeUseCaseCamera(
-    override var runningUseCases: Set = emptySet(),
     override var requestControl: UseCaseCameraRequestControl = FakeUseCaseCameraRequestControl(),
 ) : UseCaseCamera {
 
-    override var isPrimary: Boolean = true
-        set(value) {
-            field = value
-        }
-
-    override fun  setParameterAsync(
-        key: CaptureRequest.Key,
-        value: T,
-        priority: Config.OptionPriority
-    ): Deferred {
-        return CompletableDeferred(Unit)
-    }
-
-    override fun setParametersAsync(
-        values: Map, Any>,
-        priority: Config.OptionPriority
-    ): Deferred {
-        return CompletableDeferred(Unit)
-    }
-
     override fun close(): Job {
         return CompletableDeferred(Unit)
     }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeZoomCompat.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeZoomCompat.kt
index ecb8a1f..b0b62df 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeZoomCompat.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeZoomCompat.kt
@@ -18,7 +18,7 @@
 
 import android.graphics.Rect
 import androidx.camera.camera2.pipe.integration.compat.ZoomCompat
-import androidx.camera.camera2.pipe.integration.impl.UseCaseCamera
+import androidx.camera.camera2.pipe.integration.impl.UseCaseCameraRequestControl
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
 
@@ -31,7 +31,10 @@
     var zoomRatio = 0f
     var applyAsyncResult = CompletableDeferred(Unit) // already completed deferred
 
-    override fun applyAsync(zoomRatio: Float, camera: UseCaseCamera): Deferred {
+    override fun applyAsync(
+        zoomRatio: Float,
+        requestControl: UseCaseCameraRequestControl
+    ): Deferred {
         return applyAsyncResult.also { result ->
             result.invokeOnCompletion { this.zoomRatio = zoomRatio }
         }
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/StreamConfigurationMapUtil.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/StreamConfigurationMapUtil.kt
new file mode 100644
index 0000000..041a376
--- /dev/null
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/StreamConfigurationMapUtil.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2024 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.camera.camera2.pipe.integration.testing
+
+import android.hardware.camera2.params.StreamConfigurationMap
+import android.os.Build
+import android.util.Size
+import android.util.SparseIntArray
+import org.robolectric.shadows.StreamConfigurationMapBuilder
+import org.robolectric.util.ReflectionHelpers
+
+/** Generates a [StreamConfigurationMap] with the given [supportedSizes]. */
+fun generateFakeStreamConfigurationMap(supportedSizes: Array): StreamConfigurationMap {
+    val map =
+        StreamConfigurationMapBuilder.newBuilder()
+            .apply { supportedSizes.forEach(::addOutputSize) }
+            .build()
+
+    // Workaround for NullPointerException in Robolectric when calling getOutputFormats(). The
+    // issue seems to be due to following formats not being handled in Robolectric.
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        ReflectionHelpers.setField(
+            StreamConfigurationMap::class.java,
+            map,
+            "mDepthOutputFormats",
+            SparseIntArray()
+        )
+    }
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+        ReflectionHelpers.setField(
+            StreamConfigurationMap::class.java,
+            map,
+            "mDynamicDepthOutputFormats",
+            SparseIntArray()
+        )
+
+        ReflectionHelpers.setField(
+            StreamConfigurationMap::class.java,
+            map,
+            "mHeicOutputFormats",
+            SparseIntArray()
+        )
+    }
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+        ReflectionHelpers.setField(
+            StreamConfigurationMap::class.java,
+            map,
+            "mJpegROutputFormats",
+            SparseIntArray()
+        )
+    }
+
+    return map
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 2f89dcf..630a50a 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -182,10 +182,10 @@
 
         if (mDynamicRangeResolver.is10BitDynamicRangeSupported()) {
             generate10BitSupportedCombinationList();
+        }
 
-            if (isUltraHdrSupported()) {
-                generateUltraHdrSupportedCombinationList();
-            }
+        if (isUltraHdrSupported()) {
+            generateUltraHdrSupportedCombinationList();
         }
 
         mIsStreamUseCaseSupported = StreamUseCaseUtil.isStreamUseCaseSupported(mCharacteristics);
@@ -288,7 +288,12 @@
 
         List supportedSurfaceCombinations = new ArrayList<>();
 
-        if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_8_BIT) {
+        if (featureSettings.isUltraHdrOn()) {
+            // For Ultra HDR output, only the default camera mode is currently supported.
+            if (featureSettings.getCameraMode() == CameraMode.DEFAULT) {
+                supportedSurfaceCombinations.addAll(mSurfaceCombinationsUltraHdr);
+            }
+        } else if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_8_BIT) {
             switch (featureSettings.getCameraMode()) {
                 case CameraMode.CONCURRENT_CAMERA:
                     supportedSurfaceCombinations = mConcurrentSurfaceCombinations;
@@ -305,11 +310,7 @@
         } else if (featureSettings.getRequiredMaxBitDepth() == DynamicRange.BIT_DEPTH_10_BIT) {
             // For 10-bit outputs, only the default camera mode is currently supported.
             if (featureSettings.getCameraMode() == CameraMode.DEFAULT) {
-                if (featureSettings.isUltraHdrOn()) {
-                    supportedSurfaceCombinations.addAll(mSurfaceCombinationsUltraHdr);
-                } else {
-                    supportedSurfaceCombinations.addAll(mSurfaceCombinations10Bit);
-                }
+                supportedSurfaceCombinations.addAll(mSurfaceCombinations10Bit);
             }
         }
 
@@ -865,6 +866,13 @@
             boolean isPreviewStabilizationOn, boolean isUltraHdrOn) {
         int requiredMaxBitDepth = getRequiredMaxBitDepth(resolvedDynamicRanges);
 
+        if (cameraMode != CameraMode.DEFAULT && isUltraHdrOn) {
+            throw new IllegalArgumentException(String.format("Camera device id is %s. Ultra HDR "
+                            + "is not currently supported in %s camera mode.",
+                    mCameraId,
+                    CameraMode.toLabelString(cameraMode)));
+        }
+
         if (cameraMode != CameraMode.DEFAULT
                 && requiredMaxBitDepth == DynamicRange.BIT_DEPTH_10_BIT) {
             throw new IllegalArgumentException(String.format("Camera device id is %s. 10 bit "
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/ZslDisablerQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/ZslDisablerQuirk.java
index 28fe77d..2f1ae09 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/ZslDisablerQuirk.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/ZslDisablerQuirk.java
@@ -27,9 +27,9 @@
 
 /**
  * 

QuirkSummary - * Bug Id: 252818931, 261744070, 319913852 - * Description: On certain devices, the captured image has color issue for reprocessing. We - * need to disable zero-shutter lag and return false for + * Bug Id: 252818931, 261744070, 319913852, 361328838 + * Description: On certain devices, the captured image has color or zoom freezing issue for + * reprocessing. We need to disable zero-shutter lag and return false for * {@link CameraInfo#isZslSupported()}. * Device(s): Samsung Fold4, Samsung s22, Xiaomi Mi 8 */ @@ -39,7 +39,9 @@ "SM-F936", "SM-S901U", "SM-S908U", - "SM-S908U1" + "SM-S908U1", + "SM-F721U1", + "SM-S928U1" ); private static final List AFFECTED_XIAOMI_MODEL = Arrays.asList(

diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
index b4059b9..d665ba5 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.kt
@@ -1739,6 +1739,7 @@
     // Resolution selection tests for Ultra HDR
     //
     // //////////////////////////////////////////////////////////////////////////////////////////
+
     @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Test
     fun checkUltraHdrCombinationsSupported() {
@@ -1768,6 +1769,33 @@
         }
     }
 
+    @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Test
+    fun checkUltraHdrCombinationsSupported_when8bit() {
+        // Device might support Ultra HDR but not 10-bit.
+        setupCameraAndInitCameraX(supportedFormats = intArrayOf(JPEG_R))
+        val supportedSurfaceCombination =
+            SupportedSurfaceCombination(
+                context,
+                DEFAULT_CAMERA_ID,
+                cameraManagerCompat!!,
+                mockCamcorderProfileHelper
+            )
+
+        GuaranteedConfigurationsUtil.getUltraHdrSupportedCombinationList().forEach {
+            assertThat(
+                    supportedSurfaceCombination.checkSupported(
+                        createFeatureSettings(
+                            requiredMaxBitDepth = BIT_DEPTH_8_BIT,
+                            isUltraHdrOn = true
+                        ),
+                        it.surfaceConfigList
+                    )
+                )
+                .isTrue()
+        }
+    }
+
     /** JPEG_R/MAXIMUM when Ultra HDR is ON. */
     @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @Test
@@ -1775,7 +1803,6 @@
         val jpegUseCase =
             createUseCase(
                 CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
                 imageFormat = JPEG_R,
             ) // JPEG
         val useCaseExpectedResultMap =
@@ -1796,7 +1823,27 @@
         val jpegUseCase =
             createUseCase(
                 CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
+                imageFormat = JPEG_R,
+            ) // JPEG
+        val useCaseExpectedResultMap =
+            mutableMapOf().apply {
+                put(privUseCase, PREVIEW_SIZE)
+                put(jpegUseCase, MAXIMUM_SIZE)
+            }
+        getSuggestedSpecsAndVerify(
+            useCasesExpectedSizeMap = useCaseExpectedResultMap,
+            supportedOutputFormats = intArrayOf(JPEG_R),
+        )
+    }
+
+    /** HLG10 PRIV/PREVIEW + JPEG_R/MAXIMUM when Ultra HDR is ON. */
+    @Config(minSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Test
+    fun canSelectCorrectSizes_hlg10PrivPlusJpegr_whenUltraHdrIsOn() {
+        val privUseCase = createUseCase(CaptureType.PREVIEW, dynamicRange = HLG_10_BIT) // PRIV
+        val jpegUseCase =
+            createUseCase(
+                CaptureType.IMAGE_CAPTURE,
                 imageFormat = JPEG_R,
             ) // JPEG
         val useCaseExpectedResultMap =
@@ -1821,7 +1868,6 @@
         val jpegUseCase =
             createUseCase(
                 CaptureType.IMAGE_CAPTURE,
-                dynamicRange = HLG_10_BIT,
                 imageFormat = JPEG_R,
             ) // JPEG
         val useCaseExpectedResultMap =
@@ -3489,10 +3535,8 @@
             set(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL, hardwareLevel)
             set(CameraCharacteristics.SENSOR_ORIENTATION, sensorOrientation)
             set(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize)
-            // Only setup stream configuration map when the supported output sizes are specified.
-            supportedSizes?.let {
-                set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP, mockMap)
-            }
+            // Setup stream configuration map, no matter supported output sizes are specified.
+            set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP, mockMap)
             set(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, deviceFPSRanges)
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                 dynamicRangeProfiles?.let {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 5c15ced..20b2ecd 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -19,7 +19,6 @@
 import static android.graphics.ImageFormat.JPEG_R;
 
 import static androidx.camera.core.CameraEffect.IMAGE_CAPTURE;
-import static androidx.camera.core.DynamicRange.HDR_UNSPECIFIED_10_BIT;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_BUFFER_FORMAT;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_CAPTURE_CONFIG_UNPACKER;
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_DEFAULT_CAPTURE_CONFIG;
@@ -472,7 +471,7 @@
             if (isOutputFormatUltraHdr(builder.getMutableConfig())) {
                 builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT, JPEG_R);
                 builder.getMutableConfig().insertOption(OPTION_INPUT_DYNAMIC_RANGE,
-                        HDR_UNSPECIFIED_10_BIT);
+                        DynamicRange.UNSPECIFIED);
             } else if (useSoftwareJpeg) {
                 builder.getMutableConfig().insertOption(OPTION_INPUT_FORMAT,
                         ImageFormat.YUV_420_888);
@@ -2323,7 +2322,7 @@
                 if (isOutputFormatUltraHdr(getMutableConfig())) {
                     getMutableConfig().insertOption(OPTION_INPUT_FORMAT, JPEG_R);
                     getMutableConfig().insertOption(OPTION_INPUT_DYNAMIC_RANGE,
-                            HDR_UNSPECIFIED_10_BIT);
+                            DynamicRange.UNSPECIFIED);
                 } else {
                     getMutableConfig().insertOption(OPTION_INPUT_FORMAT, ImageFormat.JPEG);
                 }
@@ -2829,14 +2828,6 @@
          *
          * 

If not set, the output format will default to {@link #OUTPUT_FORMAT_JPEG}. * - *

If an Ultra HDR output format is used, a {@link DynamicRange#HDR_UNSPECIFIED_10_BIT} - * will be used as the dynamic range of this use case. Please note that some devices may not - * be able to support configuring both SDR and HDR use cases at the same time, e.g. use - * Ultra HDR ImageCapture with a SDR Preview. Configuring concurrent SDR and HDR on these - * devices will result in an {@link IllegalArgumentException} to be thrown when invoking - * {@code bindToLifecycle()}. Such device specific constraints can be queried by calling - * {@link android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints(long)}. - * * @param outputFormat The output image format. Value is {@link #OUTPUT_FORMAT_JPEG} or * {@link #OUTPUT_FORMAT_JPEG_ULTRA_HDR}. * @return The current Builder.

diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index 541a169..dc922ee 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -1031,9 +1031,16 @@
         // TODO(b/309900490): since there are other places (e.g. SupportedSurfaceCombination in
         //  camera2) that feature combination constraints are enforced, it would be nice if they
         //  followed a similar pattern for checking constraints.
-        if (hasExtension() && hasNonSdrConfig(useCases)) {
-            throw new IllegalArgumentException("Extensions are only supported for use with "
-                    + "standard dynamic range.");
+        if (hasExtension()) {
+            if (hasNonSdrConfig(useCases)) {
+                throw new IllegalArgumentException("Extensions are only supported for use with "
+                        + "standard dynamic range.");
+            }
+
+            if (hasUltraHdrImageCapture(useCases)) {
+                throw new IllegalArgumentException("Extensions are not supported for use with "
+                        + "Ultra HDR image capture.");
+            }
         }
 
         // TODO(b/322311893): throw exception to block feature combination of effect with Ultra
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/DeviceCompatibilityTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/DeviceCompatibilityTest.kt
deleted file mode 100644
index c8a2dbb..0000000
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/DeviceCompatibilityTest.kt
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright 2022 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.camera.video
-
-import android.content.Context
-import android.media.MediaCodec
-import android.media.MediaCodecInfo
-import android.os.Build
-import androidx.camera.camera2.Camera2Config
-import androidx.camera.camera2.pipe.integration.CameraPipeConfig
-import androidx.camera.core.CameraSelector
-import androidx.camera.core.CameraSelector.DEFAULT_BACK_CAMERA
-import androidx.camera.core.CameraSelector.DEFAULT_FRONT_CAMERA
-import androidx.camera.core.CameraXConfig
-import androidx.camera.core.impl.EncoderProfilesProxy.VideoProfileProxy
-import androidx.camera.testing.impl.CameraPipeConfigTestRule
-import androidx.camera.testing.impl.CameraUtil
-import androidx.camera.testing.impl.CameraXUtil
-import androidx.camera.video.internal.VideoValidatedEncoderProfilesProxy
-import androidx.camera.video.internal.compat.quirk.DeviceQuirks
-import androidx.camera.video.internal.compat.quirk.MediaCodecInfoReportIncorrectInfoQuirk
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
-import com.google.common.collect.Range
-import com.google.common.truth.Truth.assertWithMessage
-import java.util.concurrent.TimeUnit
-import org.junit.After
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-/**
- * Test used to find out compatibility issue.
- *
- * All tests in this file should always pass. Every time we want to add a new test, it means there
- * is also a corresponding quirk in the codebase and we want to find more devices with the same root
- * cause. Tests should use [assumeTrue] to skip related quirks so that the problematic device will
- * pass the test. Once a new failure is found in the mobile harness test results, we should add the
- * device to the relevant quirk to pass the test.
- */
-@SmallTest
-@RunWith(Parameterized::class)
-@SdkSuppress(minSdkVersion = 21)
-class DeviceCompatibilityTest(
-    private val implName: String,
-    private val cameraConfig: CameraXConfig,
-) {
-
-    private val context: Context = ApplicationProvider.getApplicationContext()
-    private val zeroRange by lazy { android.util.Range.create(0, 0) }
-
-    @get:Rule
-    val cameraPipeConfigTestRule =
-        CameraPipeConfigTestRule(
-            active = implName == CameraPipeConfig::class.simpleName,
-        )
-
-    @get:Rule
-    val cameraRule =
-        CameraUtil.grantCameraPermissionAndPreTestAndPostTest(
-            CameraUtil.PreTestCameraIdList(cameraConfig)
-        )
-
-    @Before
-    fun setup() {
-        CameraXUtil.initialize(context, cameraConfig).get()
-    }
-
-    @After
-    fun tearDown() {
-        CameraXUtil.shutdown().get(10, TimeUnit.SECONDS)
-    }
-
-    @Test
-    fun mediaCodecInfoShouldSupportEncoderProfilesSizes() {
-        assumeTrue(DeviceQuirks.get(MediaCodecInfoReportIncorrectInfoQuirk::class.java) == null)
-
-        // Arrange: Collect all supported profiles from default back/front camera.
-        val supportedProfiles = mutableListOf()
-        supportedProfiles.addAll(getSupportedProfiles(DEFAULT_BACK_CAMERA))
-        supportedProfiles.addAll(getSupportedProfiles(DEFAULT_FRONT_CAMERA))
-        assumeTrue(supportedProfiles.isNotEmpty())
-
-        supportedProfiles.forEach { profile ->
-            // Arrange: Find the codec and its video capabilities.
-            // If mime is null, skip the test instead of failing it since this isn't the purpose
-            // of the test.
-            val videoProfile = profile.defaultVideoProfile
-            val mime = videoProfile.mediaType
-            if (mime == VideoProfileProxy.MEDIA_TYPE_NONE) {
-                return@forEach
-            }
-            val capabilities =
-                MediaCodec.createEncoderByType(mime).let { codec ->
-                    try {
-                        codec.codecInfo.getCapabilitiesForType(mime).videoCapabilities
-                    } finally {
-                        codec.release()
-                    }
-                }
-
-            // Act.
-            val (width, height) = videoProfile.width to videoProfile.height
-            // Pass if VideoCapabilities.isSizeSupported() is true
-            if (capabilities.isSizeSupported(width, height)) {
-                return@forEach
-            }
-
-            val supportedWidths = capabilities.supportedWidths
-            val supportedHeights = capabilities.supportedHeights
-            val supportedWidthsForHeight = capabilities.getWidthsForHeightQuietly(height)
-            val supportedHeightForWidth = capabilities.getHeightsForWidthQuietly(width)
-
-            // Assert.
-            val msg =
-                "Build.BRAND: ${Build.BRAND}, Build.MODEL: ${Build.MODEL} " +
-                    "mime: $mime, size: ${width}x$height is not in " +
-                    "supported widths $supportedWidths/$supportedWidthsForHeight " +
-                    "or heights $supportedHeights/$supportedHeightForWidth, " +
-                    "the width/height alignment is " +
-                    "${capabilities.widthAlignment}/${capabilities.heightAlignment}."
-            assertWithMessage(msg).that(width).isIn(supportedWidths.toClosed())
-            assertWithMessage(msg).that(height).isIn(supportedHeights.toClosed())
-            assertWithMessage(msg).that(width).isIn(supportedWidthsForHeight.toClosed())
-            assertWithMessage(msg).that(height).isIn(supportedHeightForWidth.toClosed())
-        }
-    }
-
-    private fun getSupportedProfiles(
-        cameraSelector: CameraSelector
-    ): List {
-        if (!CameraUtil.hasCameraWithLensFacing(cameraSelector.lensFacing!!)) {
-            return emptyList()
-        }
-
-        val cameraInfo = CameraUtil.createCameraUseCaseAdapter(context, cameraSelector).cameraInfo
-        val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
-
-        return videoCapabilities.supportedDynamicRanges.flatMap { dynamicRange ->
-            videoCapabilities.getSupportedQualities(dynamicRange).map { quality ->
-                videoCapabilities.getProfiles(quality, dynamicRange)!!
-            }
-        }
-    }
-
-    private fun android.util.Range.toClosed() = Range.closed(lower, upper)
-
-    private fun MediaCodecInfo.VideoCapabilities.getWidthsForHeightQuietly(
-        height: Int
-    ): android.util.Range {
-        return try {
-            getSupportedWidthsFor(height)
-        } catch (e: IllegalArgumentException) {
-            zeroRange
-        }
-    }
-
-    private fun MediaCodecInfo.VideoCapabilities.getHeightsForWidthQuietly(
-        width: Int
-    ): android.util.Range {
-        return try {
-            getSupportedHeightsFor(width)
-        } catch (e: IllegalArgumentException) {
-            zeroRange
-        }
-    }
-
-    companion object {
-        @JvmStatic
-        @Parameterized.Parameters(name = "{0}")
-        fun data() =
-            listOf(
-                arrayOf(Camera2Config::class.simpleName, Camera2Config.defaultConfig()),
-                arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
-            )
-    }
-}
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
index a1c2869..3b491b0 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
@@ -17,9 +17,11 @@
 
 import android.Manifest
 import android.content.Context
-import android.hardware.camera2.CameraCaptureSession
-import android.hardware.camera2.CaptureRequest
-import android.hardware.camera2.TotalCaptureResult
+import android.graphics.SurfaceTexture
+import android.os.Handler
+import android.os.HandlerThread
+import android.util.Log
+import android.view.Surface
 import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.pipe.integration.CameraPipeConfig
 import androidx.camera.core.Camera
@@ -33,12 +35,12 @@
 import androidx.camera.core.ImageProxy
 import androidx.camera.core.Preview
 import androidx.camera.core.UseCase
-import androidx.camera.integration.core.util.CameraPipeUtil
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.impl.AndroidUtil.skipVideoRecordingTestIfNotSupportedByEmulator
 import androidx.camera.testing.impl.CameraPipeConfigTestRule
 import androidx.camera.testing.impl.CameraUtil
-import androidx.camera.testing.impl.SurfaceTextureProvider.createSurfaceTextureProvider
+import androidx.camera.testing.impl.GLUtil
 import androidx.camera.testing.impl.WakelockEmptyActivityRule
 import androidx.camera.testing.impl.fakes.FakeLifecycleOwner
 import androidx.camera.testing.impl.video.AudioChecker
@@ -98,6 +100,8 @@
     @get:Rule val wakelockEmptyActivityRule = WakelockEmptyActivityRule()
 
     companion object {
+        private const val TAG = "UseCaseCombinationTest"
+
         @JvmStatic
         @Parameterized.Parameters(name = "{0}")
         fun data() =
@@ -448,22 +452,12 @@
         imageAnalysisMonitor.waitForImageAnalysis()
     }
 
-    private fun initPreview(monitor: PreviewMonitor?, setSurfaceProvider: Boolean = true): Preview {
-        return Preview.Builder()
-            .setTargetName("Preview")
-            .also {
-                monitor?.let { monitor ->
-                    CameraPipeUtil.setCameraCaptureSessionCallback(implName, it, monitor)
-                }
+    private fun initPreview(monitor: PreviewMonitor, setSurfaceProvider: Boolean = true): Preview {
+        return Preview.Builder().setTargetName("Preview").build().apply {
+            if (setSurfaceProvider) {
+                instrumentation.runOnMainSync { surfaceProvider = monitor.getSurfaceProvider() }
             }
-            .build()
-            .apply {
-                if (setSurfaceProvider) {
-                    instrumentation.runOnMainSync {
-                        surfaceProvider = createSurfaceTextureProvider()
-                    }
-                }
-            }
+        }
     }
 
     private fun initImageAnalysis(analyzer: ImageAnalysis.Analyzer?): ImageAnalysis {
@@ -501,8 +495,51 @@
             .isTrue()
     }
 
-    class PreviewMonitor : CameraCaptureSession.CaptureCallback() {
+    class PreviewMonitor {
         private var countDown: CountDownLatch? = null
+        private val surfaceProvider =
+            Preview.SurfaceProvider { request ->
+                val lock = Any()
+                var surfaceTextureReleased = false
+                val surfaceTexture = SurfaceTexture(0)
+                surfaceTexture.setDefaultBufferSize(
+                    request.resolution.width,
+                    request.resolution.height
+                )
+                surfaceTexture.detachFromGLContext()
+                surfaceTexture.attachToGLContext(GLUtil.getTexIdFromGLContext())
+                val frameUpdateThread = HandlerThread("frameUpdateThread").apply { start() }
+
+                surfaceTexture.setOnFrameAvailableListener(
+                    {
+                        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+                            synchronized(lock) {
+                                if (!surfaceTextureReleased) {
+                                    try {
+                                        surfaceTexture.updateTexImage()
+                                    } catch (e: IllegalStateException) {
+                                        Log.e(TAG, "updateTexImage failed!")
+                                    }
+                                }
+                            }
+                        }
+                        countDown?.countDown()
+                    },
+                    Handler(frameUpdateThread.getLooper())
+                )
+
+                val surface = Surface(surfaceTexture)
+                request.provideSurface(surface, CameraXExecutors.directExecutor()) {
+                    synchronized(lock) {
+                        surfaceTextureReleased = true
+                        surface.release()
+                        surfaceTexture.release()
+                        frameUpdateThread.quitSafely()
+                    }
+                }
+            }
+
+        fun getSurfaceProvider(): Preview.SurfaceProvider = surfaceProvider
 
         fun waitForStream(count: Int = 10, timeMillis: Long = TimeUnit.SECONDS.toMillis(5)) {
             Truth.assertWithMessage("Preview doesn't start")
@@ -540,14 +577,6 @@
                     countDown
                 }!!
                 .await(timeSeconds, TimeUnit.SECONDS)
-
-        override fun onCaptureCompleted(
-            session: CameraCaptureSession,
-            request: CaptureRequest,
-            result: TotalCaptureResult
-        ) {
-            synchronized(this) { countDown?.countDown() }
-        }
     }
 
     class AnalysisMonitor : ImageAnalysis.Analyzer {
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
index 331ed44..b7f221e 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
@@ -29,6 +29,7 @@
 import androidx.camera.testing.impl.CameraPipeConfigTestRule
 import androidx.camera.testing.impl.CameraUtil
 import androidx.camera.testing.impl.CoreAppTestUtil
+import androidx.camera.testing.impl.InternalTestConvenience.useInCameraTest
 import androidx.camera.view.PreviewView
 import androidx.lifecycle.Lifecycle.State
 import androidx.test.core.app.ActivityScenario
@@ -135,7 +136,7 @@
     // The test makes sure the camera PreviewView is in the streaming state.
     @Test
     fun testPreviewViewUpdateAfterStopResume() {
-        launchActivity(lensFacing, cameraXConfig).use { scenario ->
+        launchActivity(lensFacing, cameraXConfig).useInCameraTest { scenario ->
             // At first, check Preview in stream state
             assertStreamState(scenario, PreviewView.StreamState.STREAMING)
 
@@ -152,7 +153,7 @@
     // The test makes sure the TextureView surface texture keeps the same after switch.
     @Test
     fun testPreviewViewUpdateAfterSwitch() {
-        launchActivity(lensFacing, cameraXConfig).use { scenario ->
+        launchActivity(lensFacing, cameraXConfig).useInCameraTest { scenario ->
             // At first, check Preview in stream state
             assertStreamState(scenario, PreviewView.StreamState.STREAMING)
 
@@ -175,7 +176,7 @@
     )
     @Test
     fun testPreviewViewUpdateAfterSwitchOutAndStop_ResumeAndSwitchBack() {
-        launchActivity(lensFacing, cameraXConfig).use { scenario ->
+        launchActivity(lensFacing, cameraXConfig).useInCameraTest { scenario ->
             // At first, check Preview in stream state
             assertStreamState(scenario, PreviewView.StreamState.STREAMING)
 
diff --git a/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java b/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java
index 2959671..1f975fd2 100644
--- a/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java
+++ b/car/app/app/src/main/java/androidx/car/app/messaging/model/ConversationItem.java
@@ -32,8 +32,6 @@
 import androidx.car.app.model.CarIcon;
 import androidx.car.app.model.CarText;
 import androidx.car.app.model.Item;
-import androidx.car.app.model.Row;
-import androidx.car.app.model.Template;
 import androidx.car.app.model.constraints.ActionsConstraints;
 import androidx.car.app.utils.CollectionUtils;
 import androidx.core.app.Person;
@@ -199,17 +197,9 @@
     }
 
     /**
-     * Returns whether this item should be included in an indexed list.
+     * Returns whether this item can be included in indexed lists.
      *
-     * 

"Indexing" refers to the process of examining list contents (e.g. item titles) to sort, - * partition, or filter a list. Indexing is generally used for features called "Accelerators", - * which allow a user to quickly find a particular {@link Item} in a long list. - * - *

To exclude a single item from indexed lists and accelerator features, use - * {@link Row.Builder#setIndexable(boolean)}. - * - *

To enable/disable accelerators for the entire list, see the API for the particular - * list-like {@link Template} that you are using. + * @see Builder#setIndexable(boolean) */ @ExperimentalCarApi public boolean isIndexable() { @@ -343,7 +333,26 @@ return this; } - /** @see #isIndexable */ + /** + * Sets whether this item can be included in indexed lists. By default, this is set to + * {@code true}. + * + *

The host creates indexed lists to help users navigate through long lists more easily + * by sorting, filtering, or some other means. + * + *

For example, a media app may, by default, show a user's playlists sorted by date + * created. If the app provides these playlists via the {@code SectionedItemTemplate} and + * enables {@code #isAlphabeticalIndexingAllowed}, the user will be able to jump to their + * playlists that start with the letter "H". When this happens, the list is reconstructed + * and sorted alphabetically, then shown to the user, jumping down to the letter "H". If + * the item is set to {@code #setIndexable(false)}, the item will not show up in this newly + * sorted list. + * + *

Individual items can be set to be included or excluded from filtered lists, but it's + * also possible to enable/disable the creation of filtered lists as a whole via the + * template's API (eg. {@code SectionedItemTemplate + * .Builder#setAlphabeticalIndexingAllowed(Boolean)}). + */ @ExperimentalCarApi @NonNull public Builder setIndexable(boolean indexable) {

diff --git a/car/app/app/src/main/java/androidx/car/app/model/GridItem.java b/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
index 0645006..7e1e705 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/GridItem.java
@@ -157,17 +157,9 @@
     }
 
     /**
-     * Returns whether this item should be included in an indexed list.
+     * Returns whether this item can be included in indexed lists.
      *
-     * 

"Indexing" refers to the process of examining list contents (e.g. item titles) to sort, - * partition, or filter a list. Indexing is generally used for features called "Accelerators", - * which allow a user to quickly find a particular {@link Item} in a long list. - * - *

To exclude a single item from indexed lists and accelerator features, use - * {@link Row.Builder#setIndexable(boolean)}. - * - *

To enable/disable accelerators for the entire list, see the API for the particular - * list-like {@link Template} that you are using. + * @see Builder#setIndexable(boolean) */ @ExperimentalCarApi public boolean isIndexable() { @@ -261,7 +253,7 @@ boolean mIsLoading; @Nullable Badge mBadge; - boolean mIndexable; + boolean mIndexable = true; /** * Sets whether the item is in a loading state. @@ -454,7 +446,27 @@ return this; } - /** @see #isIndexable */ + /** + * Sets whether this item can be included in indexed lists. By default, this is set to + * {@code true}. + * + *

The host creates indexed lists to help users navigate through long lists more easily + * by sorting, filtering, or some other means. + * + *

For example, a media app may, by default, show a user's playlists sorted by date + * created. If the app provides these playlists via the {@code SectionedItemTemplate} and + * enables {@code #isAlphabeticalIndexingAllowed}, the user will be able to select a letter + * on a keyboard to jump to their playlists that start with that letter. When this happens, + * the list is reconstructed and sorted alphabetically, then shown to the user, jumping down + * to the letter. Items that are set to {@code #setIndexable(false)}, do not show up in this + * new sorted list. Sticking with the media example, a media app may choose to hide things + * like "autogenerated playlists" from the list and only keep user created playlists. + * + *

Individual items can be set to be included or excluded from filtered lists, but it's + * also possible to enable/disable the creation of filtered lists as a whole via the + * template's API (eg. {@code SectionedItemTemplate + * .Builder#setAlphabeticalIndexingAllowed(Boolean)}). + */ @ExperimentalCarApi @NonNull public Builder setIndexable(boolean indexable) {

diff --git a/car/app/app/src/main/java/androidx/car/app/model/Row.java b/car/app/app/src/main/java/androidx/car/app/model/Row.java
index 46835b3..1ab8b4f 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Row.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Row.java
@@ -249,17 +249,9 @@
     }
 
     /**
-     * Returns whether this item should be included in an indexed list.
+     * Returns whether this item can be included in indexed lists.
      *
-     * 

"Indexing" refers to the process of examining list contents (e.g. item titles) to sort, - * partition, or filter a list. Indexing is generally used for features called "Accelerators", - * which allow a user to quickly find a particular {@link Item} in a long list. - * - *

To exclude a single item from indexed lists and accelerator features, use - * {@link Row.Builder#setIndexable(boolean)}. - * - *

To enable/disable accelerators for the entire list, see the API for the particular - * list-like {@link Template} that you are using. + * @see Builder#setIndexable(boolean) */ @ExperimentalCarApi public boolean isIndexable() { @@ -694,7 +686,27 @@ return this; } - /** @see #isIndexable */ + /** + * Sets whether this item can be included in indexed lists. By default, this is set to + * {@code true}. + * + *

The host creates indexed lists to help users navigate through long lists more easily + * by sorting, filtering, or some other means. + * + *

For example, a media app may, by default, show a user's playlists sorted by date + * created. If the app provides these playlists via the {@code SectionedItemTemplate} and + * enables {@code #isAlphabeticalIndexingAllowed}, the user will be able to select a letter + * on a keyboard to jump to their playlists that start with that letter. When this happens, + * the list is reconstructed and sorted alphabetically, then shown to the user, jumping down + * to the letter. Items that are set to {@code #setIndexable(false)}, do not show up in this + * new sorted list. Sticking with the media example, a media app may choose to hide things + * like "autogenerated playlists" from the list and only keep user created playlists. + * + *

Individual items can be set to be included or excluded from filtered lists, but it's + * also possible to enable/disable the creation of filtered lists as a whole via the + * template's API (eg. {@code SectionedItemTemplate + * .Builder#setAlphabeticalIndexingAllowed(Boolean)}). + */ @ExperimentalCarApi @NonNull public Builder setIndexable(boolean indexable) {

diff --git a/car/app/app/src/main/java/androidx/car/app/model/SectionedItemTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/SectionedItemTemplate.java
index 9f1b19c0..694b82d 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/SectionedItemTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/SectionedItemTemplate.java
@@ -262,7 +262,7 @@
 
         /**
          * Sets whether or not this template is in a loading state. If passed {@code true}, sections
-         * cannot be added to the template.
+         * cannot be added to the template. By default, this is {@code false}.
          */
         @NonNull
         @CanIgnoreReturnValue
@@ -272,15 +272,22 @@
         }
 
         /**
-         * Sets whether this list can be indexed alphabetically, by item title.
+         * Sets whether this list can be indexed alphabetically, by item title. By default, this
+         * is {@code false}.
          *
          * 

"Indexing" refers to the process of examining list contents (e.g. item titles) to - * sort, - * partition, or filter a list. Indexing is generally used for features called - * "Accelerators", - * which allow a user to quickly find a particular {@link Item} in a long list. + * sort, partition, or filter a list. Indexing is generally used for features called + * "Accelerators", which allow a user to quickly find a particular {@link Item} in a long + * list. * - *

To exclude a single item from indexing, see the relevant item's API. + *

For example, a media app may, by default, show a user's playlists sorted by date + * created. If the app provides these playlists via the {@code SectionedItemTemplate} and + * enables {@link #isAlphabeticalIndexingAllowed}, the user will be able to jump to their + * playlists that start with the letter "H". When this happens, the list is reconstructed + * and sorted alphabetically, then shown to the user, jumping down to the letter "H". + * + *

Individual items may be excluded from the list by setting their {@code #isIndexable} + * field to {@code false}. */ @NonNull @CanIgnoreReturnValue

diff --git a/collection/collection/api/current.txt b/collection/collection/api/current.txt
index 40c5ca2..688cf79 100644
--- a/collection/collection/api/current.txt
+++ b/collection/collection/api/current.txt
@@ -95,11 +95,14 @@
   }
 
   public abstract sealed class DoubleList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(double element);
     method public final boolean containsAll(androidx.collection.DoubleList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final double elementAt(@IntRange(from=0L) int index);
     method public final inline double elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -116,12 +119,12 @@
     method public final operator double get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(double element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -137,11 +140,11 @@
     method public final double last();
     method public final inline double last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(double element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
   }
 
   public final class DoubleListKt {
@@ -274,11 +277,14 @@
   }
 
   public abstract sealed class FloatList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(float element);
     method public final boolean containsAll(androidx.collection.FloatList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final float elementAt(@IntRange(from=0L) int index);
     method public final inline float elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -295,12 +301,12 @@
     method public final operator float get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(float element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -316,11 +322,11 @@
     method public final float last();
     method public final inline float last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(float element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
   }
 
   public final class FloatListKt {
@@ -602,11 +608,14 @@
   }
 
   public abstract sealed class IntList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(int element);
     method public final boolean containsAll(androidx.collection.IntList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final int elementAt(@IntRange(from=0L) int index);
     method public final inline int elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -623,12 +632,12 @@
     method public final operator int get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(int element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -644,11 +653,11 @@
     method public final int last();
     method public final inline int last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(int element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
   }
 
   public final class IntListKt {
@@ -919,11 +928,14 @@
   }
 
   public abstract sealed class LongList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(long element);
     method public final boolean containsAll(androidx.collection.LongList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final long elementAt(@IntRange(from=0L) int index);
     method public final inline long elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -940,12 +952,12 @@
     method public final operator long get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(long element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -961,11 +973,11 @@
     method public final long last();
     method public final inline long last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(long element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
   }
 
   public final class LongListKt {
@@ -1213,8 +1225,8 @@
     ctor public MutableDoubleList(optional int initialCapacity);
     method public boolean add(double element);
     method public void add(@IntRange(from=0L) int index, double element);
-    method public boolean addAll(androidx.collection.DoubleList elements);
-    method public boolean addAll(double[] elements);
+    method public inline boolean addAll(androidx.collection.DoubleList elements);
+    method public inline boolean addAll(double[] elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.DoubleList elements);
     method public boolean addAll(@IntRange(from=0L) int index, double[] elements);
     method public void clear();
@@ -1223,9 +1235,9 @@
     method public operator void minusAssign(androidx.collection.DoubleList elements);
     method public inline operator void minusAssign(double element);
     method public operator void minusAssign(double[] elements);
-    method public operator void plusAssign(androidx.collection.DoubleList elements);
+    method public inline operator void plusAssign(androidx.collection.DoubleList elements);
     method public inline operator void plusAssign(double element);
-    method public operator void plusAssign(double[] elements);
+    method public inline operator void plusAssign(double[] elements);
     method public boolean remove(double element);
     method public boolean removeAll(androidx.collection.DoubleList elements);
     method public boolean removeAll(double[] elements);
@@ -1285,8 +1297,8 @@
     ctor public MutableFloatList(optional int initialCapacity);
     method public boolean add(float element);
     method public void add(@IntRange(from=0L) int index, float element);
-    method public boolean addAll(androidx.collection.FloatList elements);
-    method public boolean addAll(float[] elements);
+    method public inline boolean addAll(androidx.collection.FloatList elements);
+    method public inline boolean addAll(float[] elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.FloatList elements);
     method public boolean addAll(@IntRange(from=0L) int index, float[] elements);
     method public void clear();
@@ -1295,9 +1307,9 @@
     method public operator void minusAssign(androidx.collection.FloatList elements);
     method public inline operator void minusAssign(float element);
     method public operator void minusAssign(float[] elements);
-    method public operator void plusAssign(androidx.collection.FloatList elements);
+    method public inline operator void plusAssign(androidx.collection.FloatList elements);
     method public inline operator void plusAssign(float element);
-    method public operator void plusAssign(float[] elements);
+    method public inline operator void plusAssign(float[] elements);
     method public boolean remove(float element);
     method public boolean removeAll(androidx.collection.FloatList elements);
     method public boolean removeAll(float[] elements);
@@ -1415,19 +1427,19 @@
     ctor public MutableIntList(optional int initialCapacity);
     method public boolean add(int element);
     method public void add(@IntRange(from=0L) int index, int element);
-    method public boolean addAll(androidx.collection.IntList elements);
+    method public inline boolean addAll(androidx.collection.IntList elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.IntList elements);
     method public boolean addAll(@IntRange(from=0L) int index, int[] elements);
-    method public boolean addAll(int[] elements);
+    method public inline boolean addAll(int[] elements);
     method public void clear();
     method public void ensureCapacity(int capacity);
     method public inline int getCapacity();
     method public operator void minusAssign(androidx.collection.IntList elements);
     method public inline operator void minusAssign(int element);
     method public operator void minusAssign(int[] elements);
-    method public operator void plusAssign(androidx.collection.IntList elements);
+    method public inline operator void plusAssign(androidx.collection.IntList elements);
     method public inline operator void plusAssign(int element);
-    method public operator void plusAssign(int[] elements);
+    method public inline operator void plusAssign(int[] elements);
     method public boolean remove(int element);
     method public boolean removeAll(androidx.collection.IntList elements);
     method public boolean removeAll(int[] elements);
@@ -1545,19 +1557,19 @@
     ctor public MutableLongList(optional int initialCapacity);
     method public void add(@IntRange(from=0L) int index, long element);
     method public boolean add(long element);
-    method public boolean addAll(androidx.collection.LongList elements);
+    method public inline boolean addAll(androidx.collection.LongList elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.LongList elements);
     method public boolean addAll(@IntRange(from=0L) int index, long[] elements);
-    method public boolean addAll(long[] elements);
+    method public inline boolean addAll(long[] elements);
     method public void clear();
     method public void ensureCapacity(int capacity);
     method public inline int getCapacity();
     method public operator void minusAssign(androidx.collection.LongList elements);
     method public inline operator void minusAssign(long element);
     method public operator void minusAssign(long[] elements);
-    method public operator void plusAssign(androidx.collection.LongList elements);
+    method public inline operator void plusAssign(androidx.collection.LongList elements);
     method public inline operator void plusAssign(long element);
-    method public operator void plusAssign(long[] elements);
+    method public inline operator void plusAssign(long[] elements);
     method public boolean remove(long element);
     method public boolean removeAll(androidx.collection.LongList elements);
     method public boolean removeAll(long[] elements);
diff --git a/collection/collection/api/restricted_current.txt b/collection/collection/api/restricted_current.txt
index 0cd8d39..b5fcbad 100644
--- a/collection/collection/api/restricted_current.txt
+++ b/collection/collection/api/restricted_current.txt
@@ -95,11 +95,14 @@
   }
 
   public abstract sealed class DoubleList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(double element);
     method public final boolean containsAll(androidx.collection.DoubleList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final double elementAt(@IntRange(from=0L) int index);
     method public final inline double elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -116,12 +119,12 @@
     method public final operator double get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(double element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -137,11 +140,11 @@
     method public final double last();
     method public final inline double last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(double element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
     field @kotlin.PublishedApi internal int _size;
     field @kotlin.PublishedApi internal double[] content;
   }
@@ -286,11 +289,14 @@
   }
 
   public abstract sealed class FloatList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(float element);
     method public final boolean containsAll(androidx.collection.FloatList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final float elementAt(@IntRange(from=0L) int index);
     method public final inline float elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -307,12 +313,12 @@
     method public final operator float get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(float element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -328,11 +334,11 @@
     method public final float last();
     method public final inline float last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(float element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
     field @kotlin.PublishedApi internal int _size;
     field @kotlin.PublishedApi internal float[] content;
   }
@@ -638,11 +644,14 @@
   }
 
   public abstract sealed class IntList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(int element);
     method public final boolean containsAll(androidx.collection.IntList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final int elementAt(@IntRange(from=0L) int index);
     method public final inline int elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -659,12 +668,12 @@
     method public final operator int get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(int element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -680,11 +689,11 @@
     method public final int last();
     method public final inline int last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(int element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
     field @kotlin.PublishedApi internal int _size;
     field @kotlin.PublishedApi internal int[] content;
   }
@@ -979,11 +988,14 @@
   }
 
   public abstract sealed class LongList {
-    method public final boolean any();
+    method public final inline boolean any();
     method public final inline boolean any(kotlin.jvm.functions.Function1 predicate);
+    method public final int binarySearch(int element);
+    method public final int binarySearch(int element, optional int fromIndex);
+    method public final int binarySearch(int element, optional int fromIndex, optional int toIndex);
     method public final operator boolean contains(long element);
     method public final boolean containsAll(androidx.collection.LongList elements);
-    method public final int count();
+    method public final inline int count();
     method public final inline int count(kotlin.jvm.functions.Function1 predicate);
     method public final long elementAt(@IntRange(from=0L) int index);
     method public final inline long elementAtOrElse(@IntRange(from=0L) int index, kotlin.jvm.functions.Function1 defaultValue);
@@ -1000,12 +1012,12 @@
     method public final operator long get(@IntRange(from=0L) int index);
     method public final inline kotlin.ranges.IntRange getIndices();
     method @IntRange(from=-1L) public final inline int getLastIndex();
-    method @IntRange(from=0L) public final int getSize();
+    method @IntRange(from=0L) public final inline int getSize();
     method public final int indexOf(long element);
     method public final inline int indexOfFirst(kotlin.jvm.functions.Function1 predicate);
     method public final inline int indexOfLast(kotlin.jvm.functions.Function1 predicate);
-    method public final boolean isEmpty();
-    method public final boolean isNotEmpty();
+    method public final inline boolean isEmpty();
+    method public final inline boolean isNotEmpty();
     method public final String joinToString();
     method public final String joinToString(optional CharSequence separator);
     method public final String joinToString(optional CharSequence separator, optional CharSequence prefix);
@@ -1021,11 +1033,11 @@
     method public final long last();
     method public final inline long last(kotlin.jvm.functions.Function1 predicate);
     method public final int lastIndexOf(long element);
-    method public final boolean none();
+    method public final inline boolean none();
     method public final inline boolean reversedAny(kotlin.jvm.functions.Function1 predicate);
     property public final inline kotlin.ranges.IntRange indices;
     property @IntRange(from=-1L) public final inline int lastIndex;
-    property @IntRange(from=0L) public final int size;
+    property @IntRange(from=0L) public final inline int size;
     field @kotlin.PublishedApi internal int _size;
     field @kotlin.PublishedApi internal long[] content;
   }
@@ -1287,8 +1299,8 @@
     ctor public MutableDoubleList(optional int initialCapacity);
     method public boolean add(double element);
     method public void add(@IntRange(from=0L) int index, double element);
-    method public boolean addAll(androidx.collection.DoubleList elements);
-    method public boolean addAll(double[] elements);
+    method public inline boolean addAll(androidx.collection.DoubleList elements);
+    method public inline boolean addAll(double[] elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.DoubleList elements);
     method public boolean addAll(@IntRange(from=0L) int index, double[] elements);
     method public void clear();
@@ -1297,9 +1309,9 @@
     method public operator void minusAssign(androidx.collection.DoubleList elements);
     method public inline operator void minusAssign(double element);
     method public operator void minusAssign(double[] elements);
-    method public operator void plusAssign(androidx.collection.DoubleList elements);
+    method public inline operator void plusAssign(androidx.collection.DoubleList elements);
     method public inline operator void plusAssign(double element);
-    method public operator void plusAssign(double[] elements);
+    method public inline operator void plusAssign(double[] elements);
     method public boolean remove(double element);
     method public boolean removeAll(androidx.collection.DoubleList elements);
     method public boolean removeAll(double[] elements);
@@ -1361,8 +1373,8 @@
     ctor public MutableFloatList(optional int initialCapacity);
     method public boolean add(float element);
     method public void add(@IntRange(from=0L) int index, float element);
-    method public boolean addAll(androidx.collection.FloatList elements);
-    method public boolean addAll(float[] elements);
+    method public inline boolean addAll(androidx.collection.FloatList elements);
+    method public inline boolean addAll(float[] elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.FloatList elements);
     method public boolean addAll(@IntRange(from=0L) int index, float[] elements);
     method public void clear();
@@ -1371,9 +1383,9 @@
     method public operator void minusAssign(androidx.collection.FloatList elements);
     method public inline operator void minusAssign(float element);
     method public operator void minusAssign(float[] elements);
-    method public operator void plusAssign(androidx.collection.FloatList elements);
+    method public inline operator void plusAssign(androidx.collection.FloatList elements);
     method public inline operator void plusAssign(float element);
-    method public operator void plusAssign(float[] elements);
+    method public inline operator void plusAssign(float[] elements);
     method public boolean remove(float element);
     method public boolean removeAll(androidx.collection.FloatList elements);
     method public boolean removeAll(float[] elements);
@@ -1495,19 +1507,19 @@
     ctor public MutableIntList(optional int initialCapacity);
     method public boolean add(int element);
     method public void add(@IntRange(from=0L) int index, int element);
-    method public boolean addAll(androidx.collection.IntList elements);
+    method public inline boolean addAll(androidx.collection.IntList elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.IntList elements);
     method public boolean addAll(@IntRange(from=0L) int index, int[] elements);
-    method public boolean addAll(int[] elements);
+    method public inline boolean addAll(int[] elements);
     method public void clear();
     method public void ensureCapacity(int capacity);
     method public inline int getCapacity();
     method public operator void minusAssign(androidx.collection.IntList elements);
     method public inline operator void minusAssign(int element);
     method public operator void minusAssign(int[] elements);
-    method public operator void plusAssign(androidx.collection.IntList elements);
+    method public inline operator void plusAssign(androidx.collection.IntList elements);
     method public inline operator void plusAssign(int element);
-    method public operator void plusAssign(int[] elements);
+    method public inline operator void plusAssign(int[] elements);
     method public boolean remove(int element);
     method public boolean removeAll(androidx.collection.IntList elements);
     method public boolean removeAll(int[] elements);
@@ -1629,19 +1641,19 @@
     ctor public MutableLongList(optional int initialCapacity);
     method public void add(@IntRange(from=0L) int index, long element);
     method public boolean add(long element);
-    method public boolean addAll(androidx.collection.LongList elements);
+    method public inline boolean addAll(androidx.collection.LongList elements);
     method public boolean addAll(@IntRange(from=0L) int index, androidx.collection.LongList elements);
     method public boolean addAll(@IntRange(from=0L) int index, long[] elements);
-    method public boolean addAll(long[] elements);
+    method public inline boolean addAll(long[] elements);
     method public void clear();
     method public void ensureCapacity(int capacity);
     method public inline int getCapacity();
     method public operator void minusAssign(androidx.collection.LongList elements);
     method public inline operator void minusAssign(long element);
     method public operator void minusAssign(long[] elements);
-    method public operator void plusAssign(androidx.collection.LongList elements);
+    method public inline operator void plusAssign(androidx.collection.LongList elements);
     method public inline operator void plusAssign(long element);
-    method public operator void plusAssign(long[] elements);
+    method public inline operator void plusAssign(long[] elements);
     method public boolean remove(long element);
     method public boolean removeAll(androidx.collection.LongList elements);
     method public boolean removeAll(long[] elements);
diff --git a/collection/collection/bcv/native/current.txt b/collection/collection/bcv/native/current.txt
index a189609..215b18d 100644
--- a/collection/collection/bcv/native/current.txt
+++ b/collection/collection/bcv/native/current.txt
@@ -468,16 +468,12 @@
 
     final fun add(kotlin/Double): kotlin/Boolean // androidx.collection/MutableDoubleList.add|add(kotlin.Double){}[0]
     final fun add(kotlin/Int, kotlin/Double) // androidx.collection/MutableDoubleList.add|add(kotlin.Int;kotlin.Double){}[0]
-    final fun addAll(androidx.collection/DoubleList): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(androidx.collection.DoubleList){}[0]
-    final fun addAll(kotlin/DoubleArray): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(kotlin.DoubleArray){}[0]
     final fun addAll(kotlin/Int, androidx.collection/DoubleList): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(kotlin.Int;androidx.collection.DoubleList){}[0]
     final fun addAll(kotlin/Int, kotlin/DoubleArray): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(kotlin.Int;kotlin.DoubleArray){}[0]
     final fun clear() // androidx.collection/MutableDoubleList.clear|clear(){}[0]
     final fun ensureCapacity(kotlin/Int) // androidx.collection/MutableDoubleList.ensureCapacity|ensureCapacity(kotlin.Int){}[0]
     final fun minusAssign(androidx.collection/DoubleList) // androidx.collection/MutableDoubleList.minusAssign|minusAssign(androidx.collection.DoubleList){}[0]
     final fun minusAssign(kotlin/DoubleArray) // androidx.collection/MutableDoubleList.minusAssign|minusAssign(kotlin.DoubleArray){}[0]
-    final fun plusAssign(androidx.collection/DoubleList) // androidx.collection/MutableDoubleList.plusAssign|plusAssign(androidx.collection.DoubleList){}[0]
-    final fun plusAssign(kotlin/DoubleArray) // androidx.collection/MutableDoubleList.plusAssign|plusAssign(kotlin.DoubleArray){}[0]
     final fun remove(kotlin/Double): kotlin/Boolean // androidx.collection/MutableDoubleList.remove|remove(kotlin.Double){}[0]
     final fun removeAll(androidx.collection/DoubleList): kotlin/Boolean // androidx.collection/MutableDoubleList.removeAll|removeAll(androidx.collection.DoubleList){}[0]
     final fun removeAll(kotlin/DoubleArray): kotlin/Boolean // androidx.collection/MutableDoubleList.removeAll|removeAll(kotlin.DoubleArray){}[0]
@@ -489,8 +485,12 @@
     final fun sort() // androidx.collection/MutableDoubleList.sort|sort(){}[0]
     final fun sortDescending() // androidx.collection/MutableDoubleList.sortDescending|sortDescending(){}[0]
     final fun trim(kotlin/Int = ...) // androidx.collection/MutableDoubleList.trim|trim(kotlin.Int){}[0]
+    final inline fun addAll(androidx.collection/DoubleList): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(androidx.collection.DoubleList){}[0]
+    final inline fun addAll(kotlin/DoubleArray): kotlin/Boolean // androidx.collection/MutableDoubleList.addAll|addAll(kotlin.DoubleArray){}[0]
     final inline fun minusAssign(kotlin/Double) // androidx.collection/MutableDoubleList.minusAssign|minusAssign(kotlin.Double){}[0]
+    final inline fun plusAssign(androidx.collection/DoubleList) // androidx.collection/MutableDoubleList.plusAssign|plusAssign(androidx.collection.DoubleList){}[0]
     final inline fun plusAssign(kotlin/Double) // androidx.collection/MutableDoubleList.plusAssign|plusAssign(kotlin.Double){}[0]
+    final inline fun plusAssign(kotlin/DoubleArray) // androidx.collection/MutableDoubleList.plusAssign|plusAssign(kotlin.DoubleArray){}[0]
 }
 
 final class androidx.collection/MutableFloatFloatMap : androidx.collection/FloatFloatMap { // androidx.collection/MutableFloatFloatMap|null[0]
@@ -543,16 +543,12 @@
 
     final fun add(kotlin/Float): kotlin/Boolean // androidx.collection/MutableFloatList.add|add(kotlin.Float){}[0]
     final fun add(kotlin/Int, kotlin/Float) // androidx.collection/MutableFloatList.add|add(kotlin.Int;kotlin.Float){}[0]
-    final fun addAll(androidx.collection/FloatList): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(androidx.collection.FloatList){}[0]
-    final fun addAll(kotlin/FloatArray): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(kotlin.FloatArray){}[0]
     final fun addAll(kotlin/Int, androidx.collection/FloatList): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(kotlin.Int;androidx.collection.FloatList){}[0]
     final fun addAll(kotlin/Int, kotlin/FloatArray): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(kotlin.Int;kotlin.FloatArray){}[0]
     final fun clear() // androidx.collection/MutableFloatList.clear|clear(){}[0]
     final fun ensureCapacity(kotlin/Int) // androidx.collection/MutableFloatList.ensureCapacity|ensureCapacity(kotlin.Int){}[0]
     final fun minusAssign(androidx.collection/FloatList) // androidx.collection/MutableFloatList.minusAssign|minusAssign(androidx.collection.FloatList){}[0]
     final fun minusAssign(kotlin/FloatArray) // androidx.collection/MutableFloatList.minusAssign|minusAssign(kotlin.FloatArray){}[0]
-    final fun plusAssign(androidx.collection/FloatList) // androidx.collection/MutableFloatList.plusAssign|plusAssign(androidx.collection.FloatList){}[0]
-    final fun plusAssign(kotlin/FloatArray) // androidx.collection/MutableFloatList.plusAssign|plusAssign(kotlin.FloatArray){}[0]
     final fun remove(kotlin/Float): kotlin/Boolean // androidx.collection/MutableFloatList.remove|remove(kotlin.Float){}[0]
     final fun removeAll(androidx.collection/FloatList): kotlin/Boolean // androidx.collection/MutableFloatList.removeAll|removeAll(androidx.collection.FloatList){}[0]
     final fun removeAll(kotlin/FloatArray): kotlin/Boolean // androidx.collection/MutableFloatList.removeAll|removeAll(kotlin.FloatArray){}[0]
@@ -564,8 +560,12 @@
     final fun sort() // androidx.collection/MutableFloatList.sort|sort(){}[0]
     final fun sortDescending() // androidx.collection/MutableFloatList.sortDescending|sortDescending(){}[0]
     final fun trim(kotlin/Int = ...) // androidx.collection/MutableFloatList.trim|trim(kotlin.Int){}[0]
+    final inline fun addAll(androidx.collection/FloatList): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(androidx.collection.FloatList){}[0]
+    final inline fun addAll(kotlin/FloatArray): kotlin/Boolean // androidx.collection/MutableFloatList.addAll|addAll(kotlin.FloatArray){}[0]
     final inline fun minusAssign(kotlin/Float) // androidx.collection/MutableFloatList.minusAssign|minusAssign(kotlin.Float){}[0]
+    final inline fun plusAssign(androidx.collection/FloatList) // androidx.collection/MutableFloatList.plusAssign|plusAssign(androidx.collection.FloatList){}[0]
     final inline fun plusAssign(kotlin/Float) // androidx.collection/MutableFloatList.plusAssign|plusAssign(kotlin.Float){}[0]
+    final inline fun plusAssign(kotlin/FloatArray) // androidx.collection/MutableFloatList.plusAssign|plusAssign(kotlin.FloatArray){}[0]
 }
 
 final class androidx.collection/MutableFloatLongMap : androidx.collection/FloatLongMap { // androidx.collection/MutableFloatLongMap|null[0]
@@ -658,16 +658,12 @@
 
     final fun add(kotlin/Int): kotlin/Boolean // androidx.collection/MutableIntList.add|add(kotlin.Int){}[0]
     final fun add(kotlin/Int, kotlin/Int) // androidx.collection/MutableIntList.add|add(kotlin.Int;kotlin.Int){}[0]
-    final fun addAll(androidx.collection/IntList): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(androidx.collection.IntList){}[0]
     final fun addAll(kotlin/Int, androidx.collection/IntList): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(kotlin.Int;androidx.collection.IntList){}[0]
     final fun addAll(kotlin/Int, kotlin/IntArray): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(kotlin.Int;kotlin.IntArray){}[0]
-    final fun addAll(kotlin/IntArray): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(kotlin.IntArray){}[0]
     final fun clear() // androidx.collection/MutableIntList.clear|clear(){}[0]
     final fun ensureCapacity(kotlin/Int) // androidx.collection/MutableIntList.ensureCapacity|ensureCapacity(kotlin.Int){}[0]
     final fun minusAssign(androidx.collection/IntList) // androidx.collection/MutableIntList.minusAssign|minusAssign(androidx.collection.IntList){}[0]
     final fun minusAssign(kotlin/IntArray) // androidx.collection/MutableIntList.minusAssign|minusAssign(kotlin.IntArray){}[0]
-    final fun plusAssign(androidx.collection/IntList) // androidx.collection/MutableIntList.plusAssign|plusAssign(androidx.collection.IntList){}[0]
-    final fun plusAssign(kotlin/IntArray) // androidx.collection/MutableIntList.plusAssign|plusAssign(kotlin.IntArray){}[0]
     final fun remove(kotlin/Int): kotlin/Boolean // androidx.collection/MutableIntList.remove|remove(kotlin.Int){}[0]
     final fun removeAll(androidx.collection/IntList): kotlin/Boolean // androidx.collection/MutableIntList.removeAll|removeAll(androidx.collection.IntList){}[0]
     final fun removeAll(kotlin/IntArray): kotlin/Boolean // androidx.collection/MutableIntList.removeAll|removeAll(kotlin.IntArray){}[0]
@@ -679,8 +675,12 @@
     final fun sort() // androidx.collection/MutableIntList.sort|sort(){}[0]
     final fun sortDescending() // androidx.collection/MutableIntList.sortDescending|sortDescending(){}[0]
     final fun trim(kotlin/Int = ...) // androidx.collection/MutableIntList.trim|trim(kotlin.Int){}[0]
+    final inline fun addAll(androidx.collection/IntList): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(androidx.collection.IntList){}[0]
+    final inline fun addAll(kotlin/IntArray): kotlin/Boolean // androidx.collection/MutableIntList.addAll|addAll(kotlin.IntArray){}[0]
     final inline fun minusAssign(kotlin/Int) // androidx.collection/MutableIntList.minusAssign|minusAssign(kotlin.Int){}[0]
+    final inline fun plusAssign(androidx.collection/IntList) // androidx.collection/MutableIntList.plusAssign|plusAssign(androidx.collection.IntList){}[0]
     final inline fun plusAssign(kotlin/Int) // androidx.collection/MutableIntList.plusAssign|plusAssign(kotlin.Int){}[0]
+    final inline fun plusAssign(kotlin/IntArray) // androidx.collection/MutableIntList.plusAssign|plusAssign(kotlin.IntArray){}[0]
 }
 
 final class androidx.collection/MutableIntLongMap : androidx.collection/IntLongMap { // androidx.collection/MutableIntLongMap|null[0]
@@ -773,16 +773,12 @@
 
     final fun add(kotlin/Int, kotlin/Long) // androidx.collection/MutableLongList.add|add(kotlin.Int;kotlin.Long){}[0]
     final fun add(kotlin/Long): kotlin/Boolean // androidx.collection/MutableLongList.add|add(kotlin.Long){}[0]
-    final fun addAll(androidx.collection/LongList): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(androidx.collection.LongList){}[0]
     final fun addAll(kotlin/Int, androidx.collection/LongList): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(kotlin.Int;androidx.collection.LongList){}[0]
     final fun addAll(kotlin/Int, kotlin/LongArray): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(kotlin.Int;kotlin.LongArray){}[0]
-    final fun addAll(kotlin/LongArray): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(kotlin.LongArray){}[0]
     final fun clear() // androidx.collection/MutableLongList.clear|clear(){}[0]
     final fun ensureCapacity(kotlin/Int) // androidx.collection/MutableLongList.ensureCapacity|ensureCapacity(kotlin.Int){}[0]
     final fun minusAssign(androidx.collection/LongList) // androidx.collection/MutableLongList.minusAssign|minusAssign(androidx.collection.LongList){}[0]
     final fun minusAssign(kotlin/LongArray) // androidx.collection/MutableLongList.minusAssign|minusAssign(kotlin.LongArray){}[0]
-    final fun plusAssign(androidx.collection/LongList) // androidx.collection/MutableLongList.plusAssign|plusAssign(androidx.collection.LongList){}[0]
-    final fun plusAssign(kotlin/LongArray) // androidx.collection/MutableLongList.plusAssign|plusAssign(kotlin.LongArray){}[0]
     final fun remove(kotlin/Long): kotlin/Boolean // androidx.collection/MutableLongList.remove|remove(kotlin.Long){}[0]
     final fun removeAll(androidx.collection/LongList): kotlin/Boolean // androidx.collection/MutableLongList.removeAll|removeAll(androidx.collection.LongList){}[0]
     final fun removeAll(kotlin/LongArray): kotlin/Boolean // androidx.collection/MutableLongList.removeAll|removeAll(kotlin.LongArray){}[0]
@@ -794,8 +790,12 @@
     final fun sort() // androidx.collection/MutableLongList.sort|sort(){}[0]
     final fun sortDescending() // androidx.collection/MutableLongList.sortDescending|sortDescending(){}[0]
     final fun trim(kotlin/Int = ...) // androidx.collection/MutableLongList.trim|trim(kotlin.Int){}[0]
+    final inline fun addAll(androidx.collection/LongList): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(androidx.collection.LongList){}[0]
+    final inline fun addAll(kotlin/LongArray): kotlin/Boolean // androidx.collection/MutableLongList.addAll|addAll(kotlin.LongArray){}[0]
     final inline fun minusAssign(kotlin/Long) // androidx.collection/MutableLongList.minusAssign|minusAssign(kotlin.Long){}[0]
+    final inline fun plusAssign(androidx.collection/LongList) // androidx.collection/MutableLongList.plusAssign|plusAssign(androidx.collection.LongList){}[0]
     final inline fun plusAssign(kotlin/Long) // androidx.collection/MutableLongList.plusAssign|plusAssign(kotlin.Long){}[0]
+    final inline fun plusAssign(kotlin/LongArray) // androidx.collection/MutableLongList.plusAssign|plusAssign(kotlin.LongArray){}[0]
 }
 
 final class androidx.collection/MutableLongLongMap : androidx.collection/LongLongMap { // androidx.collection/MutableLongLongMap|null[0]
@@ -1439,7 +1439,7 @@
     final val lastIndex // androidx.collection/DoubleList.lastIndex|{}lastIndex[0]
         final inline fun (): kotlin/Int // androidx.collection/DoubleList.lastIndex.|(){}[0]
     final val size // androidx.collection/DoubleList.size|{}size[0]
-        final fun (): kotlin/Int // androidx.collection/DoubleList.size.|(){}[0]
+        final inline fun (): kotlin/Int // androidx.collection/DoubleList.size.|(){}[0]
 
     final var _size // androidx.collection/DoubleList._size|{}_size[0]
         final fun (): kotlin/Int // androidx.collection/DoubleList._size.|(){}[0]
@@ -1448,25 +1448,23 @@
         final fun (): kotlin/DoubleArray // androidx.collection/DoubleList.content.|(){}[0]
         final fun (kotlin/DoubleArray) // androidx.collection/DoubleList.content.|(kotlin.DoubleArray){}[0]
 
-    final fun any(): kotlin/Boolean // androidx.collection/DoubleList.any|any(){}[0]
+    final fun binarySearch(kotlin/Int, kotlin/Int = ..., kotlin/Int = ...): kotlin/Int // androidx.collection/DoubleList.binarySearch|binarySearch(kotlin.Int;kotlin.Int;kotlin.Int){}[0]
     final fun contains(kotlin/Double): kotlin/Boolean // androidx.collection/DoubleList.contains|contains(kotlin.Double){}[0]
     final fun containsAll(androidx.collection/DoubleList): kotlin/Boolean // androidx.collection/DoubleList.containsAll|containsAll(androidx.collection.DoubleList){}[0]
-    final fun count(): kotlin/Int // androidx.collection/DoubleList.count|count(){}[0]
     final fun elementAt(kotlin/Int): kotlin/Double // androidx.collection/DoubleList.elementAt|elementAt(kotlin.Int){}[0]
     final fun first(): kotlin/Double // androidx.collection/DoubleList.first|first(){}[0]
     final fun get(kotlin/Int): kotlin/Double // androidx.collection/DoubleList.get|get(kotlin.Int){}[0]
     final fun indexOf(kotlin/Double): kotlin/Int // androidx.collection/DoubleList.indexOf|indexOf(kotlin.Double){}[0]
-    final fun isEmpty(): kotlin/Boolean // androidx.collection/DoubleList.isEmpty|isEmpty(){}[0]
-    final fun isNotEmpty(): kotlin/Boolean // androidx.collection/DoubleList.isNotEmpty|isNotEmpty(){}[0]
     final fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ...): kotlin/String // androidx.collection/DoubleList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence){}[0]
     final fun last(): kotlin/Double // androidx.collection/DoubleList.last|last(){}[0]
     final fun lastIndexOf(kotlin/Double): kotlin/Int // androidx.collection/DoubleList.lastIndexOf|lastIndexOf(kotlin.Double){}[0]
-    final fun none(): kotlin/Boolean // androidx.collection/DoubleList.none|none(){}[0]
     final inline fun <#A1: kotlin/Any?> fold(#A1, kotlin/Function2<#A1, kotlin/Double, #A1>): #A1 // androidx.collection/DoubleList.fold|fold(0:0;kotlin.Function2<0:0,kotlin.Double,0:0>){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/DoubleList.foldIndexed|foldIndexed(0:0;kotlin.Function3){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRight(#A1, kotlin/Function2): #A1 // androidx.collection/DoubleList.foldRight|foldRight(0:0;kotlin.Function2){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRightIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/DoubleList.foldRightIndexed|foldRightIndexed(0:0;kotlin.Function3){0§}[0]
+    final inline fun any(): kotlin/Boolean // androidx.collection/DoubleList.any|any(){}[0]
     final inline fun any(kotlin/Function1): kotlin/Boolean // androidx.collection/DoubleList.any|any(kotlin.Function1){}[0]
+    final inline fun count(): kotlin/Int // androidx.collection/DoubleList.count|count(){}[0]
     final inline fun count(kotlin/Function1): kotlin/Int // androidx.collection/DoubleList.count|count(kotlin.Function1){}[0]
     final inline fun elementAtOrElse(kotlin/Int, kotlin/Function1): kotlin/Double // androidx.collection/DoubleList.elementAtOrElse|elementAtOrElse(kotlin.Int;kotlin.Function1){}[0]
     final inline fun first(kotlin/Function1): kotlin/Double // androidx.collection/DoubleList.first|first(kotlin.Function1){}[0]
@@ -1476,8 +1474,11 @@
     final inline fun forEachReversedIndexed(kotlin/Function2) // androidx.collection/DoubleList.forEachReversedIndexed|forEachReversedIndexed(kotlin.Function2){}[0]
     final inline fun indexOfFirst(kotlin/Function1): kotlin/Int // androidx.collection/DoubleList.indexOfFirst|indexOfFirst(kotlin.Function1){}[0]
     final inline fun indexOfLast(kotlin/Function1): kotlin/Int // androidx.collection/DoubleList.indexOfLast|indexOfLast(kotlin.Function1){}[0]
+    final inline fun isEmpty(): kotlin/Boolean // androidx.collection/DoubleList.isEmpty|isEmpty(){}[0]
+    final inline fun isNotEmpty(): kotlin/Boolean // androidx.collection/DoubleList.isNotEmpty|isNotEmpty(){}[0]
     final inline fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ..., crossinline kotlin/Function1): kotlin/String // androidx.collection/DoubleList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence;kotlin.Function1){}[0]
     final inline fun last(kotlin/Function1): kotlin/Double // androidx.collection/DoubleList.last|last(kotlin.Function1){}[0]
+    final inline fun none(): kotlin/Boolean // androidx.collection/DoubleList.none|none(){}[0]
     final inline fun reversedAny(kotlin/Function1): kotlin/Boolean // androidx.collection/DoubleList.reversedAny|reversedAny(kotlin.Function1){}[0]
     open fun equals(kotlin/Any?): kotlin/Boolean // androidx.collection/DoubleList.equals|equals(kotlin.Any?){}[0]
     open fun hashCode(): kotlin/Int // androidx.collection/DoubleList.hashCode|hashCode(){}[0]
@@ -1580,7 +1581,7 @@
     final val lastIndex // androidx.collection/FloatList.lastIndex|{}lastIndex[0]
         final inline fun (): kotlin/Int // androidx.collection/FloatList.lastIndex.|(){}[0]
     final val size // androidx.collection/FloatList.size|{}size[0]
-        final fun (): kotlin/Int // androidx.collection/FloatList.size.|(){}[0]
+        final inline fun (): kotlin/Int // androidx.collection/FloatList.size.|(){}[0]
 
     final var _size // androidx.collection/FloatList._size|{}_size[0]
         final fun (): kotlin/Int // androidx.collection/FloatList._size.|(){}[0]
@@ -1589,25 +1590,23 @@
         final fun (): kotlin/FloatArray // androidx.collection/FloatList.content.|(){}[0]
         final fun (kotlin/FloatArray) // androidx.collection/FloatList.content.|(kotlin.FloatArray){}[0]
 
-    final fun any(): kotlin/Boolean // androidx.collection/FloatList.any|any(){}[0]
+    final fun binarySearch(kotlin/Int, kotlin/Int = ..., kotlin/Int = ...): kotlin/Int // androidx.collection/FloatList.binarySearch|binarySearch(kotlin.Int;kotlin.Int;kotlin.Int){}[0]
     final fun contains(kotlin/Float): kotlin/Boolean // androidx.collection/FloatList.contains|contains(kotlin.Float){}[0]
     final fun containsAll(androidx.collection/FloatList): kotlin/Boolean // androidx.collection/FloatList.containsAll|containsAll(androidx.collection.FloatList){}[0]
-    final fun count(): kotlin/Int // androidx.collection/FloatList.count|count(){}[0]
     final fun elementAt(kotlin/Int): kotlin/Float // androidx.collection/FloatList.elementAt|elementAt(kotlin.Int){}[0]
     final fun first(): kotlin/Float // androidx.collection/FloatList.first|first(){}[0]
     final fun get(kotlin/Int): kotlin/Float // androidx.collection/FloatList.get|get(kotlin.Int){}[0]
     final fun indexOf(kotlin/Float): kotlin/Int // androidx.collection/FloatList.indexOf|indexOf(kotlin.Float){}[0]
-    final fun isEmpty(): kotlin/Boolean // androidx.collection/FloatList.isEmpty|isEmpty(){}[0]
-    final fun isNotEmpty(): kotlin/Boolean // androidx.collection/FloatList.isNotEmpty|isNotEmpty(){}[0]
     final fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ...): kotlin/String // androidx.collection/FloatList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence){}[0]
     final fun last(): kotlin/Float // androidx.collection/FloatList.last|last(){}[0]
     final fun lastIndexOf(kotlin/Float): kotlin/Int // androidx.collection/FloatList.lastIndexOf|lastIndexOf(kotlin.Float){}[0]
-    final fun none(): kotlin/Boolean // androidx.collection/FloatList.none|none(){}[0]
     final inline fun <#A1: kotlin/Any?> fold(#A1, kotlin/Function2<#A1, kotlin/Float, #A1>): #A1 // androidx.collection/FloatList.fold|fold(0:0;kotlin.Function2<0:0,kotlin.Float,0:0>){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/FloatList.foldIndexed|foldIndexed(0:0;kotlin.Function3){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRight(#A1, kotlin/Function2): #A1 // androidx.collection/FloatList.foldRight|foldRight(0:0;kotlin.Function2){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRightIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/FloatList.foldRightIndexed|foldRightIndexed(0:0;kotlin.Function3){0§}[0]
+    final inline fun any(): kotlin/Boolean // androidx.collection/FloatList.any|any(){}[0]
     final inline fun any(kotlin/Function1): kotlin/Boolean // androidx.collection/FloatList.any|any(kotlin.Function1){}[0]
+    final inline fun count(): kotlin/Int // androidx.collection/FloatList.count|count(){}[0]
     final inline fun count(kotlin/Function1): kotlin/Int // androidx.collection/FloatList.count|count(kotlin.Function1){}[0]
     final inline fun elementAtOrElse(kotlin/Int, kotlin/Function1): kotlin/Float // androidx.collection/FloatList.elementAtOrElse|elementAtOrElse(kotlin.Int;kotlin.Function1){}[0]
     final inline fun first(kotlin/Function1): kotlin/Float // androidx.collection/FloatList.first|first(kotlin.Function1){}[0]
@@ -1617,8 +1616,11 @@
     final inline fun forEachReversedIndexed(kotlin/Function2) // androidx.collection/FloatList.forEachReversedIndexed|forEachReversedIndexed(kotlin.Function2){}[0]
     final inline fun indexOfFirst(kotlin/Function1): kotlin/Int // androidx.collection/FloatList.indexOfFirst|indexOfFirst(kotlin.Function1){}[0]
     final inline fun indexOfLast(kotlin/Function1): kotlin/Int // androidx.collection/FloatList.indexOfLast|indexOfLast(kotlin.Function1){}[0]
+    final inline fun isEmpty(): kotlin/Boolean // androidx.collection/FloatList.isEmpty|isEmpty(){}[0]
+    final inline fun isNotEmpty(): kotlin/Boolean // androidx.collection/FloatList.isNotEmpty|isNotEmpty(){}[0]
     final inline fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ..., crossinline kotlin/Function1): kotlin/String // androidx.collection/FloatList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence;kotlin.Function1){}[0]
     final inline fun last(kotlin/Function1): kotlin/Float // androidx.collection/FloatList.last|last(kotlin.Function1){}[0]
+    final inline fun none(): kotlin/Boolean // androidx.collection/FloatList.none|none(){}[0]
     final inline fun reversedAny(kotlin/Function1): kotlin/Boolean // androidx.collection/FloatList.reversedAny|reversedAny(kotlin.Function1){}[0]
     open fun equals(kotlin/Any?): kotlin/Boolean // androidx.collection/FloatList.equals|equals(kotlin.Any?){}[0]
     open fun hashCode(): kotlin/Int // androidx.collection/FloatList.hashCode|hashCode(){}[0]
@@ -1800,7 +1802,7 @@
     final val lastIndex // androidx.collection/IntList.lastIndex|{}lastIndex[0]
         final inline fun (): kotlin/Int // androidx.collection/IntList.lastIndex.|(){}[0]
     final val size // androidx.collection/IntList.size|{}size[0]
-        final fun (): kotlin/Int // androidx.collection/IntList.size.|(){}[0]
+        final inline fun (): kotlin/Int // androidx.collection/IntList.size.|(){}[0]
 
     final var _size // androidx.collection/IntList._size|{}_size[0]
         final fun (): kotlin/Int // androidx.collection/IntList._size.|(){}[0]
@@ -1809,25 +1811,23 @@
         final fun (): kotlin/IntArray // androidx.collection/IntList.content.|(){}[0]
         final fun (kotlin/IntArray) // androidx.collection/IntList.content.|(kotlin.IntArray){}[0]
 
-    final fun any(): kotlin/Boolean // androidx.collection/IntList.any|any(){}[0]
+    final fun binarySearch(kotlin/Int, kotlin/Int = ..., kotlin/Int = ...): kotlin/Int // androidx.collection/IntList.binarySearch|binarySearch(kotlin.Int;kotlin.Int;kotlin.Int){}[0]
     final fun contains(kotlin/Int): kotlin/Boolean // androidx.collection/IntList.contains|contains(kotlin.Int){}[0]
     final fun containsAll(androidx.collection/IntList): kotlin/Boolean // androidx.collection/IntList.containsAll|containsAll(androidx.collection.IntList){}[0]
-    final fun count(): kotlin/Int // androidx.collection/IntList.count|count(){}[0]
     final fun elementAt(kotlin/Int): kotlin/Int // androidx.collection/IntList.elementAt|elementAt(kotlin.Int){}[0]
     final fun first(): kotlin/Int // androidx.collection/IntList.first|first(){}[0]
     final fun get(kotlin/Int): kotlin/Int // androidx.collection/IntList.get|get(kotlin.Int){}[0]
     final fun indexOf(kotlin/Int): kotlin/Int // androidx.collection/IntList.indexOf|indexOf(kotlin.Int){}[0]
-    final fun isEmpty(): kotlin/Boolean // androidx.collection/IntList.isEmpty|isEmpty(){}[0]
-    final fun isNotEmpty(): kotlin/Boolean // androidx.collection/IntList.isNotEmpty|isNotEmpty(){}[0]
     final fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ...): kotlin/String // androidx.collection/IntList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence){}[0]
     final fun last(): kotlin/Int // androidx.collection/IntList.last|last(){}[0]
     final fun lastIndexOf(kotlin/Int): kotlin/Int // androidx.collection/IntList.lastIndexOf|lastIndexOf(kotlin.Int){}[0]
-    final fun none(): kotlin/Boolean // androidx.collection/IntList.none|none(){}[0]
     final inline fun <#A1: kotlin/Any?> fold(#A1, kotlin/Function2<#A1, kotlin/Int, #A1>): #A1 // androidx.collection/IntList.fold|fold(0:0;kotlin.Function2<0:0,kotlin.Int,0:0>){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/IntList.foldIndexed|foldIndexed(0:0;kotlin.Function3){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRight(#A1, kotlin/Function2): #A1 // androidx.collection/IntList.foldRight|foldRight(0:0;kotlin.Function2){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRightIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/IntList.foldRightIndexed|foldRightIndexed(0:0;kotlin.Function3){0§}[0]
+    final inline fun any(): kotlin/Boolean // androidx.collection/IntList.any|any(){}[0]
     final inline fun any(kotlin/Function1): kotlin/Boolean // androidx.collection/IntList.any|any(kotlin.Function1){}[0]
+    final inline fun count(): kotlin/Int // androidx.collection/IntList.count|count(){}[0]
     final inline fun count(kotlin/Function1): kotlin/Int // androidx.collection/IntList.count|count(kotlin.Function1){}[0]
     final inline fun elementAtOrElse(kotlin/Int, kotlin/Function1): kotlin/Int // androidx.collection/IntList.elementAtOrElse|elementAtOrElse(kotlin.Int;kotlin.Function1){}[0]
     final inline fun first(kotlin/Function1): kotlin/Int // androidx.collection/IntList.first|first(kotlin.Function1){}[0]
@@ -1837,8 +1837,11 @@
     final inline fun forEachReversedIndexed(kotlin/Function2) // androidx.collection/IntList.forEachReversedIndexed|forEachReversedIndexed(kotlin.Function2){}[0]
     final inline fun indexOfFirst(kotlin/Function1): kotlin/Int // androidx.collection/IntList.indexOfFirst|indexOfFirst(kotlin.Function1){}[0]
     final inline fun indexOfLast(kotlin/Function1): kotlin/Int // androidx.collection/IntList.indexOfLast|indexOfLast(kotlin.Function1){}[0]
+    final inline fun isEmpty(): kotlin/Boolean // androidx.collection/IntList.isEmpty|isEmpty(){}[0]
+    final inline fun isNotEmpty(): kotlin/Boolean // androidx.collection/IntList.isNotEmpty|isNotEmpty(){}[0]
     final inline fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ..., crossinline kotlin/Function1): kotlin/String // androidx.collection/IntList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence;kotlin.Function1){}[0]
     final inline fun last(kotlin/Function1): kotlin/Int // androidx.collection/IntList.last|last(kotlin.Function1){}[0]
+    final inline fun none(): kotlin/Boolean // androidx.collection/IntList.none|none(){}[0]
     final inline fun reversedAny(kotlin/Function1): kotlin/Boolean // androidx.collection/IntList.reversedAny|reversedAny(kotlin.Function1){}[0]
     open fun equals(kotlin/Any?): kotlin/Boolean // androidx.collection/IntList.equals|equals(kotlin.Any?){}[0]
     open fun hashCode(): kotlin/Int // androidx.collection/IntList.hashCode|hashCode(){}[0]
@@ -2020,7 +2023,7 @@
     final val lastIndex // androidx.collection/LongList.lastIndex|{}lastIndex[0]
         final inline fun (): kotlin/Int // androidx.collection/LongList.lastIndex.|(){}[0]
     final val size // androidx.collection/LongList.size|{}size[0]
-        final fun (): kotlin/Int // androidx.collection/LongList.size.|(){}[0]
+        final inline fun (): kotlin/Int // androidx.collection/LongList.size.|(){}[0]
 
     final var _size // androidx.collection/LongList._size|{}_size[0]
         final fun (): kotlin/Int // androidx.collection/LongList._size.|(){}[0]
@@ -2029,25 +2032,23 @@
         final fun (): kotlin/LongArray // androidx.collection/LongList.content.|(){}[0]
         final fun (kotlin/LongArray) // androidx.collection/LongList.content.|(kotlin.LongArray){}[0]
 
-    final fun any(): kotlin/Boolean // androidx.collection/LongList.any|any(){}[0]
+    final fun binarySearch(kotlin/Int, kotlin/Int = ..., kotlin/Int = ...): kotlin/Int // androidx.collection/LongList.binarySearch|binarySearch(kotlin.Int;kotlin.Int;kotlin.Int){}[0]
     final fun contains(kotlin/Long): kotlin/Boolean // androidx.collection/LongList.contains|contains(kotlin.Long){}[0]
     final fun containsAll(androidx.collection/LongList): kotlin/Boolean // androidx.collection/LongList.containsAll|containsAll(androidx.collection.LongList){}[0]
-    final fun count(): kotlin/Int // androidx.collection/LongList.count|count(){}[0]
     final fun elementAt(kotlin/Int): kotlin/Long // androidx.collection/LongList.elementAt|elementAt(kotlin.Int){}[0]
     final fun first(): kotlin/Long // androidx.collection/LongList.first|first(){}[0]
     final fun get(kotlin/Int): kotlin/Long // androidx.collection/LongList.get|get(kotlin.Int){}[0]
     final fun indexOf(kotlin/Long): kotlin/Int // androidx.collection/LongList.indexOf|indexOf(kotlin.Long){}[0]
-    final fun isEmpty(): kotlin/Boolean // androidx.collection/LongList.isEmpty|isEmpty(){}[0]
-    final fun isNotEmpty(): kotlin/Boolean // androidx.collection/LongList.isNotEmpty|isNotEmpty(){}[0]
     final fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ...): kotlin/String // androidx.collection/LongList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence){}[0]
     final fun last(): kotlin/Long // androidx.collection/LongList.last|last(){}[0]
     final fun lastIndexOf(kotlin/Long): kotlin/Int // androidx.collection/LongList.lastIndexOf|lastIndexOf(kotlin.Long){}[0]
-    final fun none(): kotlin/Boolean // androidx.collection/LongList.none|none(){}[0]
     final inline fun <#A1: kotlin/Any?> fold(#A1, kotlin/Function2<#A1, kotlin/Long, #A1>): #A1 // androidx.collection/LongList.fold|fold(0:0;kotlin.Function2<0:0,kotlin.Long,0:0>){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/LongList.foldIndexed|foldIndexed(0:0;kotlin.Function3){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRight(#A1, kotlin/Function2): #A1 // androidx.collection/LongList.foldRight|foldRight(0:0;kotlin.Function2){0§}[0]
     final inline fun <#A1: kotlin/Any?> foldRightIndexed(#A1, kotlin/Function3): #A1 // androidx.collection/LongList.foldRightIndexed|foldRightIndexed(0:0;kotlin.Function3){0§}[0]
+    final inline fun any(): kotlin/Boolean // androidx.collection/LongList.any|any(){}[0]
     final inline fun any(kotlin/Function1): kotlin/Boolean // androidx.collection/LongList.any|any(kotlin.Function1){}[0]
+    final inline fun count(): kotlin/Int // androidx.collection/LongList.count|count(){}[0]
     final inline fun count(kotlin/Function1): kotlin/Int // androidx.collection/LongList.count|count(kotlin.Function1){}[0]
     final inline fun elementAtOrElse(kotlin/Int, kotlin/Function1): kotlin/Long // androidx.collection/LongList.elementAtOrElse|elementAtOrElse(kotlin.Int;kotlin.Function1){}[0]
     final inline fun first(kotlin/Function1): kotlin/Long // androidx.collection/LongList.first|first(kotlin.Function1){}[0]
@@ -2057,8 +2058,11 @@
     final inline fun forEachReversedIndexed(kotlin/Function2) // androidx.collection/LongList.forEachReversedIndexed|forEachReversedIndexed(kotlin.Function2){}[0]
     final inline fun indexOfFirst(kotlin/Function1): kotlin/Int // androidx.collection/LongList.indexOfFirst|indexOfFirst(kotlin.Function1){}[0]
     final inline fun indexOfLast(kotlin/Function1): kotlin/Int // androidx.collection/LongList.indexOfLast|indexOfLast(kotlin.Function1){}[0]
+    final inline fun isEmpty(): kotlin/Boolean // androidx.collection/LongList.isEmpty|isEmpty(){}[0]
+    final inline fun isNotEmpty(): kotlin/Boolean // androidx.collection/LongList.isNotEmpty|isNotEmpty(){}[0]
     final inline fun joinToString(kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/CharSequence = ..., kotlin/Int = ..., kotlin/CharSequence = ..., crossinline kotlin/Function1): kotlin/String // androidx.collection/LongList.joinToString|joinToString(kotlin.CharSequence;kotlin.CharSequence;kotlin.CharSequence;kotlin.Int;kotlin.CharSequence;kotlin.Function1){}[0]
     final inline fun last(kotlin/Function1): kotlin/Long // androidx.collection/LongList.last|last(kotlin.Function1){}[0]
+    final inline fun none(): kotlin/Boolean // androidx.collection/LongList.none|none(){}[0]
     final inline fun reversedAny(kotlin/Function1): kotlin/Boolean // androidx.collection/LongList.reversedAny|reversedAny(kotlin.Function1){}[0]
     open fun equals(kotlin/Any?): kotlin/Boolean // androidx.collection/LongList.equals|equals(kotlin.Any?){}[0]
     open fun hashCode(): kotlin/Int // androidx.collection/LongList.hashCode|hashCode(){}[0]
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
index 14dab7f..5da46d1 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/DoubleList.kt
@@ -60,7 +60,7 @@
 
     /** The number of elements in the [DoubleList]. */
     @get:IntRange(from = 0)
-    public val size: Int
+    public inline val size: Int
         get() = _size
 
     /**
@@ -75,12 +75,12 @@
         get() = 0 until _size
 
     /** Returns `true` if the collection has no elements in it. */
-    public fun none(): Boolean {
+    public inline fun none(): Boolean {
         return isEmpty()
     }
 
     /** Returns `true` if there's at least one element in the collection. */
-    public fun any(): Boolean {
+    public inline fun any(): Boolean {
         return isNotEmpty()
     }
 
@@ -131,7 +131,7 @@
     }
 
     /** Returns the number of elements in this list. */
-    public fun count(): Int = _size
+    public inline fun count(): Int = _size
 
     /**
      * Counts the number of elements matching [predicate].
@@ -290,7 +290,7 @@
      */
     public operator fun get(@IntRange(from = 0) index: Int): Double {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -301,7 +301,7 @@
      */
     public fun elementAt(@IntRange(from = 0) index: Int): Double {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -363,10 +363,10 @@
     }
 
     /** Returns `true` if the [DoubleList] has no elements in it or `false` otherwise. */
-    public fun isEmpty(): Boolean = _size == 0
+    public inline fun isEmpty(): Boolean = _size == 0
 
     /** Returns `true` if there are elements in the [DoubleList] or `false` if it is empty. */
-    public fun isNotEmpty(): Boolean = _size != 0
+    public inline fun isNotEmpty(): Boolean = _size != 0
 
     /**
      * Returns the last element in the [DoubleList] or throws a [NoSuchElementException] if it
@@ -409,6 +409,43 @@
     }
 
     /**
+     * Searches this list the specified element in the range defined by [fromIndex] and [toIndex].
+     * The list is expected to be sorted into ascending order according to the natural ordering of
+     * its elements, otherwise the result is undefined.
+     *
+     * [fromIndex] must be >= 0 and < [toIndex], and [toIndex] must be <= [size], otherwise an an
+     * [IndexOutOfBoundsException] will be thrown.
+     *
+     * @return the index of the element if it is contained in the list within the specified range.
+     *   otherwise, the inverted insertion point `(-insertionPoint - 1)`. The insertion point is
+     *   defined as the index at which the element should be inserted, so that the list remains
+     *   sorted.
+     */
+    @JvmOverloads
+    public fun binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
+        if (fromIndex < 0 || fromIndex >= toIndex || toIndex > _size) {
+            throwIndexOutOfBoundsException("")
+        }
+
+        var low = fromIndex
+        var high = toIndex - 1
+
+        while (low <= high) {
+            val mid = low + high ushr 1
+            val midVal = content[mid]
+            if (midVal < element) {
+                low = mid + 1
+            } else if (midVal > element) {
+                high = mid - 1
+            } else {
+                return mid // key found
+            }
+        }
+
+        return -(low + 1) // key not found.
+    }
+
+    /**
      * Creates a String from the elements separated by [separator] and using [prefix] before and
      * [postfix] after, if supplied.
      *
@@ -539,7 +576,7 @@
      */
     public fun add(@IntRange(from = 0) index: Int, element: Double) {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         ensureCapacity(_size + 1)
         val content = content
@@ -564,7 +601,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: DoubleArray): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements.size)
@@ -591,7 +628,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: DoubleList): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements._size)
@@ -618,7 +655,7 @@
      * Adds all [elements] to the end of the [MutableDoubleList] and returns `true` if the
      * [MutableDoubleList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: DoubleList): Boolean {
+    public inline fun addAll(elements: DoubleList): Boolean {
         return addAll(_size, elements)
     }
 
@@ -626,17 +663,17 @@
      * Adds all [elements] to the end of the [MutableDoubleList] and returns `true` if the
      * [MutableDoubleList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: DoubleArray): Boolean {
+    public inline fun addAll(elements: DoubleArray): Boolean {
         return addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableDoubleList]. */
-    public operator fun plusAssign(elements: DoubleList) {
+    public inline operator fun plusAssign(elements: DoubleList) {
         addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableDoubleList]. */
-    public operator fun plusAssign(elements: DoubleArray) {
+    public inline operator fun plusAssign(elements: DoubleArray) {
         addAll(_size, elements)
     }
 
@@ -740,7 +777,7 @@
      */
     public fun removeAt(@IntRange(from = 0) index: Int): Double {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val item = content[index]
@@ -764,10 +801,10 @@
      */
     public fun removeRange(@IntRange(from = 0) start: Int, @IntRange(from = 0) end: Int) {
         if (start !in 0.._size || end !in 0.._size) {
-            throwIndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (end < start) {
-            throwIllegalArgumentException("Start ($start) is more than end ($end)")
+            throwIllegalArgumentException("")
         }
         if (end != start) {
             if (end < _size) {
@@ -824,7 +861,7 @@
      */
     public operator fun set(@IntRange(from = 0) index: Int, element: Double): Double {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val old = content[index]
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
index 55812f3..f8fa448 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/FloatList.kt
@@ -60,7 +60,7 @@
 
     /** The number of elements in the [FloatList]. */
     @get:IntRange(from = 0)
-    public val size: Int
+    public inline val size: Int
         get() = _size
 
     /** Returns the last valid index in the [FloatList]. This can be `-1` when the list is empty. */
@@ -73,12 +73,12 @@
         get() = 0 until _size
 
     /** Returns `true` if the collection has no elements in it. */
-    public fun none(): Boolean {
+    public inline fun none(): Boolean {
         return isEmpty()
     }
 
     /** Returns `true` if there's at least one element in the collection. */
-    public fun any(): Boolean {
+    public inline fun any(): Boolean {
         return isNotEmpty()
     }
 
@@ -129,7 +129,7 @@
     }
 
     /** Returns the number of elements in this list. */
-    public fun count(): Int = _size
+    public inline fun count(): Int = _size
 
     /**
      * Counts the number of elements matching [predicate].
@@ -288,7 +288,7 @@
      */
     public operator fun get(@IntRange(from = 0) index: Int): Float {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -299,7 +299,7 @@
      */
     public fun elementAt(@IntRange(from = 0) index: Int): Float {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -361,10 +361,10 @@
     }
 
     /** Returns `true` if the [FloatList] has no elements in it or `false` otherwise. */
-    public fun isEmpty(): Boolean = _size == 0
+    public inline fun isEmpty(): Boolean = _size == 0
 
     /** Returns `true` if there are elements in the [FloatList] or `false` if it is empty. */
-    public fun isNotEmpty(): Boolean = _size != 0
+    public inline fun isNotEmpty(): Boolean = _size != 0
 
     /**
      * Returns the last element in the [FloatList] or throws a [NoSuchElementException] if it
@@ -407,6 +407,43 @@
     }
 
     /**
+     * Searches this list the specified element in the range defined by [fromIndex] and [toIndex].
+     * The list is expected to be sorted into ascending order according to the natural ordering of
+     * its elements, otherwise the result is undefined.
+     *
+     * [fromIndex] must be >= 0 and < [toIndex], and [toIndex] must be <= [size], otherwise an an
+     * [IndexOutOfBoundsException] will be thrown.
+     *
+     * @return the index of the element if it is contained in the list within the specified range.
+     *   otherwise, the inverted insertion point `(-insertionPoint - 1)`. The insertion point is
+     *   defined as the index at which the element should be inserted, so that the list remains
+     *   sorted.
+     */
+    @JvmOverloads
+    public fun binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
+        if (fromIndex < 0 || fromIndex >= toIndex || toIndex > _size) {
+            throwIndexOutOfBoundsException("")
+        }
+
+        var low = fromIndex
+        var high = toIndex - 1
+
+        while (low <= high) {
+            val mid = low + high ushr 1
+            val midVal = content[mid]
+            if (midVal < element) {
+                low = mid + 1
+            } else if (midVal > element) {
+                high = mid - 1
+            } else {
+                return mid // key found
+            }
+        }
+
+        return -(low + 1) // key not found.
+    }
+
+    /**
      * Creates a String from the elements separated by [separator] and using [prefix] before and
      * [postfix] after, if supplied.
      *
@@ -536,7 +573,7 @@
      */
     public fun add(@IntRange(from = 0) index: Int, element: Float) {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         ensureCapacity(_size + 1)
         val content = content
@@ -561,7 +598,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: FloatArray): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements.size)
@@ -588,7 +625,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: FloatList): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements._size)
@@ -615,7 +652,7 @@
      * Adds all [elements] to the end of the [MutableFloatList] and returns `true` if the
      * [MutableFloatList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: FloatList): Boolean {
+    public inline fun addAll(elements: FloatList): Boolean {
         return addAll(_size, elements)
     }
 
@@ -623,17 +660,17 @@
      * Adds all [elements] to the end of the [MutableFloatList] and returns `true` if the
      * [MutableFloatList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: FloatArray): Boolean {
+    public inline fun addAll(elements: FloatArray): Boolean {
         return addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableFloatList]. */
-    public operator fun plusAssign(elements: FloatList) {
+    public inline operator fun plusAssign(elements: FloatList) {
         addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableFloatList]. */
-    public operator fun plusAssign(elements: FloatArray) {
+    public inline operator fun plusAssign(elements: FloatArray) {
         addAll(_size, elements)
     }
 
@@ -737,7 +774,7 @@
      */
     public fun removeAt(@IntRange(from = 0) index: Int): Float {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val item = content[index]
@@ -761,10 +798,10 @@
      */
     public fun removeRange(@IntRange(from = 0) start: Int, @IntRange(from = 0) end: Int) {
         if (start !in 0.._size || end !in 0.._size) {
-            throwIndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (end < start) {
-            throwIllegalArgumentException("Start ($start) is more than end ($end)")
+            throwIllegalArgumentException("")
         }
         if (end != start) {
             if (end < _size) {
@@ -821,7 +858,7 @@
      */
     public operator fun set(@IntRange(from = 0) index: Int, element: Float): Float {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val old = content[index]
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
index 6a05353..37f2510 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/IntList.kt
@@ -60,7 +60,7 @@
 
     /** The number of elements in the [IntList]. */
     @get:IntRange(from = 0)
-    public val size: Int
+    public inline val size: Int
         get() = _size
 
     /** Returns the last valid index in the [IntList]. This can be `-1` when the list is empty. */
@@ -73,12 +73,12 @@
         get() = 0 until _size
 
     /** Returns `true` if the collection has no elements in it. */
-    public fun none(): Boolean {
+    public inline fun none(): Boolean {
         return isEmpty()
     }
 
     /** Returns `true` if there's at least one element in the collection. */
-    public fun any(): Boolean {
+    public inline fun any(): Boolean {
         return isNotEmpty()
     }
 
@@ -129,7 +129,7 @@
     }
 
     /** Returns the number of elements in this list. */
-    public fun count(): Int = _size
+    public inline fun count(): Int = _size
 
     /**
      * Counts the number of elements matching [predicate].
@@ -288,7 +288,7 @@
      */
     public operator fun get(@IntRange(from = 0) index: Int): Int {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -299,7 +299,7 @@
      */
     public fun elementAt(@IntRange(from = 0) index: Int): Int {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -359,10 +359,10 @@
     }
 
     /** Returns `true` if the [IntList] has no elements in it or `false` otherwise. */
-    public fun isEmpty(): Boolean = _size == 0
+    public inline fun isEmpty(): Boolean = _size == 0
 
     /** Returns `true` if there are elements in the [IntList] or `false` if it is empty. */
-    public fun isNotEmpty(): Boolean = _size != 0
+    public inline fun isNotEmpty(): Boolean = _size != 0
 
     /**
      * Returns the last element in the [IntList] or throws a [NoSuchElementException] if it
@@ -405,6 +405,43 @@
     }
 
     /**
+     * Searches this list the specified element in the range defined by [fromIndex] and [toIndex].
+     * The list is expected to be sorted into ascending order according to the natural ordering of
+     * its elements, otherwise the result is undefined.
+     *
+     * [fromIndex] must be >= 0 and < [toIndex], and [toIndex] must be <= [size], otherwise an an
+     * [IndexOutOfBoundsException] will be thrown.
+     *
+     * @return the index of the element if it is contained in the list within the specified range.
+     *   otherwise, the inverted insertion point `(-insertionPoint - 1)`. The insertion point is
+     *   defined as the index at which the element should be inserted, so that the list remains
+     *   sorted.
+     */
+    @JvmOverloads
+    public fun binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
+        if (fromIndex < 0 || fromIndex >= toIndex || toIndex > _size) {
+            throwIndexOutOfBoundsException("")
+        }
+
+        var low = fromIndex
+        var high = toIndex - 1
+
+        while (low <= high) {
+            val mid = low + high ushr 1
+            val midVal = content[mid]
+            if (midVal < element) {
+                low = mid + 1
+            } else if (midVal > element) {
+                high = mid - 1
+            } else {
+                return mid // key found
+            }
+        }
+
+        return -(low + 1) // key not found.
+    }
+
+    /**
      * Creates a String from the elements separated by [separator] and using [prefix] before and
      * [postfix] after, if supplied.
      *
@@ -533,7 +570,7 @@
      */
     public fun add(@IntRange(from = 0) index: Int, element: Int) {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         ensureCapacity(_size + 1)
         val content = content
@@ -558,7 +595,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: IntArray): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements.size)
@@ -585,7 +622,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: IntList): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements._size)
@@ -612,7 +649,7 @@
      * Adds all [elements] to the end of the [MutableIntList] and returns `true` if the
      * [MutableIntList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: IntList): Boolean {
+    public inline fun addAll(elements: IntList): Boolean {
         return addAll(_size, elements)
     }
 
@@ -620,17 +657,17 @@
      * Adds all [elements] to the end of the [MutableIntList] and returns `true` if the
      * [MutableIntList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: IntArray): Boolean {
+    public inline fun addAll(elements: IntArray): Boolean {
         return addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableIntList]. */
-    public operator fun plusAssign(elements: IntList) {
+    public inline operator fun plusAssign(elements: IntList) {
         addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableIntList]. */
-    public operator fun plusAssign(elements: IntArray) {
+    public inline operator fun plusAssign(elements: IntArray) {
         addAll(_size, elements)
     }
 
@@ -731,7 +768,7 @@
      */
     public fun removeAt(@IntRange(from = 0) index: Int): Int {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val item = content[index]
@@ -755,10 +792,10 @@
      */
     public fun removeRange(@IntRange(from = 0) start: Int, @IntRange(from = 0) end: Int) {
         if (start !in 0.._size || end !in 0.._size) {
-            throwIndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (end < start) {
-            throwIllegalArgumentException("Start ($start) is more than end ($end)")
+            throwIllegalArgumentException("")
         }
         if (end != start) {
             if (end < _size) {
@@ -815,7 +852,7 @@
      */
     public operator fun set(@IntRange(from = 0) index: Int, element: Int): Int {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val old = content[index]
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
index b80e23b..522220b 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/LongList.kt
@@ -60,7 +60,7 @@
 
     /** The number of elements in the [LongList]. */
     @get:IntRange(from = 0)
-    public val size: Int
+    public inline val size: Int
         get() = _size
 
     /** Returns the last valid index in the [LongList]. This can be `-1` when the list is empty. */
@@ -73,12 +73,12 @@
         get() = 0 until _size
 
     /** Returns `true` if the collection has no elements in it. */
-    public fun none(): Boolean {
+    public inline fun none(): Boolean {
         return isEmpty()
     }
 
     /** Returns `true` if there's at least one element in the collection. */
-    public fun any(): Boolean {
+    public inline fun any(): Boolean {
         return isNotEmpty()
     }
 
@@ -129,7 +129,7 @@
     }
 
     /** Returns the number of elements in this list. */
-    public fun count(): Int = _size
+    public inline fun count(): Int = _size
 
     /**
      * Counts the number of elements matching [predicate].
@@ -288,7 +288,7 @@
      */
     public operator fun get(@IntRange(from = 0) index: Int): Long {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -299,7 +299,7 @@
      */
     public fun elementAt(@IntRange(from = 0) index: Int): Long {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -360,10 +360,10 @@
     }
 
     /** Returns `true` if the [LongList] has no elements in it or `false` otherwise. */
-    public fun isEmpty(): Boolean = _size == 0
+    public inline fun isEmpty(): Boolean = _size == 0
 
     /** Returns `true` if there are elements in the [LongList] or `false` if it is empty. */
-    public fun isNotEmpty(): Boolean = _size != 0
+    public inline fun isNotEmpty(): Boolean = _size != 0
 
     /**
      * Returns the last element in the [LongList] or throws a [NoSuchElementException] if it
@@ -406,6 +406,43 @@
     }
 
     /**
+     * Searches this list the specified element in the range defined by [fromIndex] and [toIndex].
+     * The list is expected to be sorted into ascending order according to the natural ordering of
+     * its elements, otherwise the result is undefined.
+     *
+     * [fromIndex] must be >= 0 and < [toIndex], and [toIndex] must be <= [size], otherwise an an
+     * [IndexOutOfBoundsException] will be thrown.
+     *
+     * @return the index of the element if it is contained in the list within the specified range.
+     *   otherwise, the inverted insertion point `(-insertionPoint - 1)`. The insertion point is
+     *   defined as the index at which the element should be inserted, so that the list remains
+     *   sorted.
+     */
+    @JvmOverloads
+    public fun binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
+        if (fromIndex < 0 || fromIndex >= toIndex || toIndex > _size) {
+            throwIndexOutOfBoundsException("")
+        }
+
+        var low = fromIndex
+        var high = toIndex - 1
+
+        while (low <= high) {
+            val mid = low + high ushr 1
+            val midVal = content[mid]
+            if (midVal < element) {
+                low = mid + 1
+            } else if (midVal > element) {
+                high = mid - 1
+            } else {
+                return mid // key found
+            }
+        }
+
+        return -(low + 1) // key not found.
+    }
+
+    /**
      * Creates a String from the elements separated by [separator] and using [prefix] before and
      * [postfix] after, if supplied.
      *
@@ -534,7 +571,7 @@
      */
     public fun add(@IntRange(from = 0) index: Int, element: Long) {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         ensureCapacity(_size + 1)
         val content = content
@@ -559,7 +596,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: LongArray): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements.size)
@@ -586,7 +623,7 @@
      */
     public fun addAll(@IntRange(from = 0) index: Int, elements: LongList): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements._size)
@@ -613,7 +650,7 @@
      * Adds all [elements] to the end of the [MutableLongList] and returns `true` if the
      * [MutableLongList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: LongList): Boolean {
+    public inline fun addAll(elements: LongList): Boolean {
         return addAll(_size, elements)
     }
 
@@ -621,17 +658,17 @@
      * Adds all [elements] to the end of the [MutableLongList] and returns `true` if the
      * [MutableLongList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: LongArray): Boolean {
+    public inline fun addAll(elements: LongArray): Boolean {
         return addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableLongList]. */
-    public operator fun plusAssign(elements: LongList) {
+    public inline operator fun plusAssign(elements: LongList) {
         addAll(_size, elements)
     }
 
     /** Adds all [elements] to the end of the [MutableLongList]. */
-    public operator fun plusAssign(elements: LongArray) {
+    public inline operator fun plusAssign(elements: LongArray) {
         addAll(_size, elements)
     }
 
@@ -733,7 +770,7 @@
      */
     public fun removeAt(@IntRange(from = 0) index: Int): Long {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val item = content[index]
@@ -757,10 +794,10 @@
      */
     public fun removeRange(@IntRange(from = 0) start: Int, @IntRange(from = 0) end: Int) {
         if (start !in 0.._size || end !in 0.._size) {
-            throwIndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (end < start) {
-            throwIllegalArgumentException("Start ($start) is more than end ($end)")
+            throwIllegalArgumentException("")
         }
         if (end != start) {
             if (end < _size) {
@@ -817,7 +854,7 @@
      */
     public operator fun set(@IntRange(from = 0) index: Int, element: Long): Long {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val old = content[index]
diff --git a/collection/collection/src/commonTest/kotlin/androidx/collection/DoubleListTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/DoubleListTest.kt
index 4bc3b68..4c324c7 100644
--- a/collection/collection/src/commonTest/kotlin/androidx/collection/DoubleListTest.kt
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/DoubleListTest.kt
@@ -713,4 +713,16 @@
         assertEquals(-1.0, l[2])
         assertEquals(10.0, l[3])
     }
+
+    @Test
+    fun binarySearchDoubleList() {
+        val l = mutableDoubleListOf(-2.0, -1.0, 2.0, 10.0, 10.0)
+        assertEquals(0, l.binarySearch(-2))
+        assertEquals(2, l.binarySearch(2))
+        assertEquals(3, l.binarySearch(10))
+
+        assertEquals(-1, l.binarySearch(-20))
+        assertEquals(-4, l.binarySearch(3))
+        assertEquals(-6, l.binarySearch(20))
+    }
 }
diff --git a/collection/collection/src/commonTest/kotlin/androidx/collection/FloatListTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/FloatListTest.kt
index cdc37e9..e1b4649c 100644
--- a/collection/collection/src/commonTest/kotlin/androidx/collection/FloatListTest.kt
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/FloatListTest.kt
@@ -713,4 +713,16 @@
         assertEquals(-1f, l[2])
         assertEquals(10f, l[3])
     }
+
+    @Test
+    fun binarySearchFloatList() {
+        val l = mutableFloatListOf(-2f, -1f, 2f, 10f, 10f)
+        assertEquals(0, l.binarySearch(-2))
+        assertEquals(2, l.binarySearch(2))
+        assertEquals(3, l.binarySearch(10))
+
+        assertEquals(-1, l.binarySearch(-20))
+        assertEquals(-4, l.binarySearch(3))
+        assertEquals(-6, l.binarySearch(20))
+    }
 }
diff --git a/collection/collection/src/commonTest/kotlin/androidx/collection/IntListTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/IntListTest.kt
index ae3bc8f4..cdc0cf9 100644
--- a/collection/collection/src/commonTest/kotlin/androidx/collection/IntListTest.kt
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/IntListTest.kt
@@ -713,4 +713,16 @@
         assertEquals(-1, l[2])
         assertEquals(10, l[3])
     }
+
+    @Test
+    fun binarySearchIntList() {
+        val l = mutableIntListOf(-2, -1, 2, 10, 10)
+        assertEquals(0, l.binarySearch(-2))
+        assertEquals(2, l.binarySearch(2))
+        assertEquals(3, l.binarySearch(10))
+
+        assertEquals(-1, l.binarySearch(-20))
+        assertEquals(-4, l.binarySearch(3))
+        assertEquals(-6, l.binarySearch(20))
+    }
 }
diff --git a/collection/collection/src/commonTest/kotlin/androidx/collection/LongListTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/LongListTest.kt
index 9fdd870..af0536e 100644
--- a/collection/collection/src/commonTest/kotlin/androidx/collection/LongListTest.kt
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/LongListTest.kt
@@ -713,4 +713,16 @@
         assertEquals(-1L, l[2])
         assertEquals(10L, l[3])
     }
+
+    @Test
+    fun binarySearchLongList() {
+        val l = mutableLongListOf(-2L, -1L, 2L, 10L, 10L)
+        assertEquals(0, l.binarySearch(-2))
+        assertEquals(2, l.binarySearch(2))
+        assertEquals(3, l.binarySearch(10))
+
+        assertEquals(-1, l.binarySearch(-20))
+        assertEquals(-4, l.binarySearch(3))
+        assertEquals(-6, l.binarySearch(20))
+    }
 }
diff --git a/collection/collection/template/PKeyList.kt.template b/collection/collection/template/PKeyList.kt.template
index 3afb59d..929c44c 100644
--- a/collection/collection/template/PKeyList.kt.template
+++ b/collection/collection/template/PKeyList.kt.template
@@ -65,7 +65,7 @@
      * The number of elements in the [PKeyList].
      */
     @get:IntRange(from = 0)
-    public val size: Int
+    public inline val size: Int
         get() = _size
 
     /**
@@ -82,14 +82,14 @@
     /**
      * Returns `true` if the collection has no elements in it.
      */
-    public fun none(): Boolean {
+    public inline fun none(): Boolean {
         return isEmpty()
     }
 
     /**
      * Returns `true` if there's at least one element in the collection.
      */
-    public fun any(): Boolean {
+    public inline fun any(): Boolean {
         return isNotEmpty()
     }
 
@@ -146,7 +146,7 @@
     /**
      * Returns the number of elements in this list.
      */
-    public fun count(): Int = _size
+    public inline fun count(): Int = _size
 
     /**
      * Counts the number of elements matching [predicate].
@@ -308,7 +308,7 @@
      */
     public operator fun get(@IntRange(from = 0) index: Int): PKey {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -319,7 +319,7 @@
      */
     public fun elementAt(@IntRange(from = 0) index: Int): PKey {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         return content[index]
     }
@@ -384,12 +384,12 @@
     /**
      * Returns `true` if the [PKeyList] has no elements in it or `false` otherwise.
      */
-    public fun isEmpty(): Boolean = _size == 0
+    public inline fun isEmpty(): Boolean = _size == 0
 
     /**
      * Returns `true` if there are elements in the [PKeyList] or `false` if it is empty.
      */
-    public fun isNotEmpty(): Boolean = _size != 0
+    public inline fun isNotEmpty(): Boolean = _size != 0
 
     /**
      * Returns the last element in the [PKeyList] or throws a [NoSuchElementException] if
@@ -431,6 +431,43 @@
     }
 
     /**
+     * Searches this list the specified element in the range defined by [fromIndex] and [toIndex].
+     * The list is expected to be sorted into ascending order according to the natural ordering of
+     * its elements, otherwise the result is undefined.
+     *
+     * [fromIndex] must be >= 0 and < [toIndex], and [toIndex] must be <= [size], otherwise an
+     * an [IndexOutOfBoundsException] will be thrown.
+     *
+     * @return the index of the element if it is contained in the list within the specified range.
+     *   otherwise, the inverted insertion point `(-insertionPoint - 1)`. The insertion point is
+     *   defined as the index at which the element should be inserted, so that the list remains
+     *   sorted.
+     */
+    @JvmOverloads
+    public fun binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
+        if (fromIndex < 0 || fromIndex >= toIndex || toIndex > _size) {
+            throwIndexOutOfBoundsException("")
+        }
+
+        var low = fromIndex
+        var high = toIndex - 1
+
+        while (low <= high) {
+            val mid = low + high ushr 1
+            val midVal = content[mid]
+            if (midVal < element) {
+                low = mid + 1
+            } else if (midVal > element) {
+                high = mid - 1
+            } else {
+                return mid // key found
+            }
+        }
+
+        return -(low + 1) // key not found.
+    }
+
+    /**
      * Creates a String from the elements separated by [separator] and using [prefix] before
      * and [postfix] after, if supplied.
      *
@@ -570,7 +607,7 @@
      */
     public fun add(@IntRange(from = 0) index: Int, element: PKey) {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         ensureCapacity(_size + 1)
         val content = content
@@ -597,7 +634,7 @@
         elements: PKeyArray
     ): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements.size)
@@ -626,7 +663,7 @@
         elements: PKeyList
     ): Boolean {
         if (index !in 0.._size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (elements.isEmpty()) return false
         ensureCapacity(_size + elements._size)
@@ -653,7 +690,7 @@
      * Adds all [elements] to the end of the [MutablePKeyList] and returns `true` if the
      * [MutablePKeyList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: PKeyList): Boolean {
+    public inline fun addAll(elements: PKeyList): Boolean {
         return addAll(_size, elements)
     }
 
@@ -661,21 +698,21 @@
      * Adds all [elements] to the end of the [MutablePKeyList] and returns `true` if the
      * [MutablePKeyList] was changed or `false` if [elements] was empty.
      */
-    public fun addAll(elements: PKeyArray): Boolean {
+    public inline fun addAll(elements: PKeyArray): Boolean {
         return addAll(_size, elements)
     }
 
     /**
      * Adds all [elements] to the end of the [MutablePKeyList].
      */
-    public operator fun plusAssign(elements: PKeyList) {
+    public inline operator fun plusAssign(elements: PKeyList) {
         addAll(_size, elements)
     }
 
     /**
      * Adds all [elements] to the end of the [MutablePKeyList].
      */
-    public operator fun plusAssign(elements: PKeyArray) {
+    public inline operator fun plusAssign(elements: PKeyArray) {
         addAll(_size, elements)
     }
 
@@ -785,7 +822,7 @@
      */
     public fun removeAt(@IntRange(from = 0) index: Int): PKey {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("Index $index must be in 0..$lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val item = content[index]
@@ -811,10 +848,10 @@
         @IntRange(from = 0) end: Int
     ) {
         if (start !in 0.._size || end !in 0.._size) {
-            throwIndexOutOfBoundsException("Start ($start) and end ($end) must be in 0..$_size")
+            throwIndexOutOfBoundsException("")
         }
         if (end < start) {
-            throwIllegalArgumentException("Start ($start) is more than end ($end)")
+            throwIllegalArgumentException("")
         }
         if (end != start) {
             if (end < _size) {
@@ -871,7 +908,7 @@
         element: PKey
     ): PKey {
         if (index !in 0 until _size) {
-            throwIndexOutOfBoundsException("set index $index must be between 0 .. $lastIndex")
+            throwIndexOutOfBoundsException("")
         }
         val content = content
         val old = content[index]
diff --git a/collection/collection/template/PKeyListTest.kt.template b/collection/collection/template/PKeyListTest.kt.template
index f316360..8f3d8e0 100644
--- a/collection/collection/template/PKeyListTest.kt.template
+++ b/collection/collection/template/PKeyListTest.kt.template
@@ -749,4 +749,17 @@
         assertEquals(-1KeySuffix, l[2])
         assertEquals(10KeySuffix, l[3])
     }
+
+    @Test
+    fun binarySearchPKeyList() {
+        val l = mutablePKeyListOf(-2KeySuffix, -1KeySuffix, 2KeySuffix, 10KeySuffix, 10KeySuffix)
+        assertEquals(0, l.binarySearch(-2))
+        assertEquals(2, l.binarySearch(2))
+        assertEquals(3, l.binarySearch(10))
+
+        assertEquals(-1, l.binarySearch(-20))
+        assertEquals(-4, l.binarySearch(3))
+        assertEquals(-6, l.binarySearch(20))
+
+    }
 }
diff --git a/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/SeekableTransitionStateTest.kt b/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/SeekableTransitionStateTest.kt
index 32d573f..8efa4d2 100644
--- a/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/SeekableTransitionStateTest.kt
+++ b/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/SeekableTransitionStateTest.kt
@@ -71,6 +71,7 @@
 import leakcanary.DetectLeaksAfterTestSuccess
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Rule
 import org.junit.Test
@@ -2474,6 +2475,46 @@
     }
 
     @Test
+    fun isRunningFalseAfterChildAnimatedVisibilityTransition() {
+        val seekableTransitionState = SeekableTransitionState(AnimStates.From)
+        lateinit var coroutineScope: CoroutineScope
+        lateinit var transition: Transition
+        var animatedVisibilityTransition: Transition<*>? = null
+
+        rule.mainClock.autoAdvance = false
+
+        rule.setContent {
+            coroutineScope = rememberCoroutineScope()
+            transition = rememberTransition(seekableTransitionState, label = "Test")
+            transition.AnimatedVisibility(
+                visible = { it == AnimStates.To },
+            ) {
+                animatedVisibilityTransition = this.transition
+                Box(Modifier.size(100.dp))
+            }
+        }
+        rule.runOnIdle {
+            assertFalse(transition.isRunning)
+            assertNull(animatedVisibilityTransition)
+        }
+
+        rule.runOnUiThread {
+            coroutineScope.launch { seekableTransitionState.animateTo(AnimStates.To) }
+        }
+        rule.mainClock.advanceTimeBy(50)
+        rule.runOnIdle {
+            assertTrue(transition.isRunning)
+            assertTrue(animatedVisibilityTransition!!.isRunning)
+        }
+
+        rule.mainClock.advanceTimeBy(5000)
+        rule.runOnIdle {
+            assertFalse(transition.isRunning)
+            assertFalse(animatedVisibilityTransition!!.isRunning)
+        }
+    }
+
+    @Test
     fun testCleanupAfterDispose() {
         fun isObserving(): Boolean {
             var active = false
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/IntListExtensionTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/IntListExtensionTest.kt
deleted file mode 100644
index a24dda5..0000000
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/IntListExtensionTest.kt
+++ /dev/null
@@ -1,52 +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.animation.core
-
-import androidx.collection.intListOf
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertThrows
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class IntListExtensionTest {
-    @Test
-    fun binarySearch() {
-        val l = intListOf(1, 3, 5)
-        assertEquals(0, l.binarySearch(1))
-        assertEquals(-2, l.binarySearch(2))
-        assertEquals(1, l.binarySearch(3))
-        assertEquals(-3, l.binarySearch(4))
-        assertEquals(2, l.binarySearch(5))
-
-        assertEquals(-2, l.binarySearch(2, fromIndex = 1))
-        assertEquals(-3, l.binarySearch(2, fromIndex = 2))
-        assertEquals(-3, l.binarySearch(5, toIndex = l.size - 1))
-
-        // toIndex is exclusive, fails with size + 1
-        assertThrows(IndexOutOfBoundsException::class.java) {
-            l.binarySearch(element = 3, toIndex = l.size + 1)
-        }
-        assertThrows(IndexOutOfBoundsException::class.java) {
-            l.binarySearch(element = 3, fromIndex = -1)
-        }
-        assertThrows(IllegalArgumentException::class.java) {
-            l.binarySearch(element = 3, fromIndex = 1, toIndex = 0)
-        }
-    }
-}
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ArcSpline.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ArcSpline.kt
index 740faa1..45dfee1 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ArcSpline.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ArcSpline.kt
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
+@file:Suppress("NOTHING_TO_INLINE")
+
 package androidx.compose.animation.core
 
+import androidx.compose.ui.util.fastCoerceIn
+import kotlin.jvm.JvmField
 import kotlin.math.PI
 import kotlin.math.abs
 import kotlin.math.cos
 import kotlin.math.hypot
+import kotlin.math.max
+import kotlin.math.min
 import kotlin.math.sin
 
 /**
@@ -41,33 +47,39 @@
         arcs =
             Array(timePoints.size - 1) { i ->
                 when (arcModes[i]) {
-                    ArcStartVertical -> {
+                    ArcSplineArcStartVertical -> {
                         mode = StartVertical
                         last = mode
                     }
-                    ArcStartHorizontal -> {
+                    ArcSplineArcStartHorizontal -> {
                         mode = StartHorizontal
                         last = mode
                     }
-                    ArcStartFlip -> {
+                    ArcSplineArcStartFlip -> {
                         mode = if (last == StartVertical) StartHorizontal else StartVertical
                         last = mode
                     }
-                    ArcStartLinear -> mode = StartLinear
-                    ArcAbove -> mode = UpArc
-                    ArcBelow -> mode = DownArc
+                    ArcSplineArcStartLinear -> mode = StartLinear
+                    ArcSplineArcAbove -> mode = UpArc
+                    ArcSplineArcBelow -> mode = DownArc
                 }
-                val dim = y[i].size / 2 + y[i].size % 2
+
+                val yArray = y[i]
+                val yArray1 = y[i + 1]
+                val timeArray = timePoints[i]
+                val timeArray1 = timePoints[i + 1]
+
+                val dim = yArray.size / 2 + yArray.size % 2
                 Array(dim) { j ->
                     val k = j * 2
                     Arc(
                         mode = mode,
-                        time1 = timePoints[i],
-                        time2 = timePoints[i + 1],
-                        x1 = y[i][k],
-                        y1 = y[i][k + 1],
-                        x2 = y[i + 1][k],
-                        y2 = y[i + 1][k + 1]
+                        time1 = timeArray,
+                        time2 = timeArray1,
+                        x1 = yArray[k],
+                        y1 = yArray[k + 1],
+                        x2 = yArray1[k],
+                        y2 = yArray1[k + 1]
                     )
                 }
             }
@@ -76,29 +88,36 @@
     /** get the values of the at t point in time. */
     fun getPos(time: Float, v: FloatArray) {
         var t = time
+        val arcs = arcs
+        val lastIndex = arcs.size - 1
+        val start = arcs[0][0].time1
+        val end = arcs[lastIndex][0].time2
+        val size = v.size
+
         if (isExtrapolate) {
-            if (t < arcs[0][0].time1 || t > arcs[arcs.size - 1][0].time2) {
+            if (t < start || t > end) {
                 val p: Int
                 val t0: Float
-                if (t > arcs[arcs.size - 1][0].time2) {
-                    p = arcs.size - 1
-                    t0 = arcs[arcs.size - 1][0].time2
+                if (t > end) {
+                    p = lastIndex
+                    t0 = end
                 } else {
                     p = 0
-                    t0 = arcs[0][0].time1
+                    t0 = start
                 }
                 val dt = t - t0
 
                 var i = 0
                 var j = 0
-                while (i < v.size) {
-                    if (arcs[p][j].isLinear) {
-                        v[i] = arcs[p][j].getLinearX(t0) + dt * arcs[p][j].getLinearDX()
-                        v[i + 1] = arcs[p][j].getLinearY(t0) + dt * arcs[p][j].getLinearDY()
+                while (i < size - 1) {
+                    val arc = arcs[p][j]
+                    if (arc.isLinear) {
+                        v[i] = arc.getLinearX(t0) + dt * arc.linearDX
+                        v[i + 1] = arc.getLinearY(t0) + dt * arc.linearDY
                     } else {
-                        arcs[p][j].setPoint(t0)
-                        v[i] = arcs[p][j].calcX() + dt * arcs[p][j].calcDX()
-                        v[i + 1] = arcs[p][j].calcY() + dt * arcs[p][j].calcDY()
+                        arc.setPoint(t0)
+                        v[i] = arc.calcX() + dt * arc.calcDX()
+                        v[i + 1] = arc.calcY() + dt * arc.calcDY()
                     }
                     i += 2
                     j++
@@ -106,12 +125,8 @@
                 return
             }
         } else {
-            if (t < arcs[0][0].time1) {
-                t = arcs[0][0].time1
-            }
-            if (t > arcs[arcs.size - 1][0].time2) {
-                t = arcs[arcs.size - 1][0].time2
-            }
+            t = max(t, start)
+            t = min(t, end)
         }
 
         // TODO: Consider passing the index from the caller to improve performance
@@ -119,18 +134,18 @@
         for (i in arcs.indices) {
             var k = 0
             var j = 0
-            while (j < v.size) {
-                if (t <= arcs[i][k].time2) {
-                    if (arcs[i][k].isLinear) {
-                        v[j] = arcs[i][k].getLinearX(t)
-                        v[j + 1] = arcs[i][k].getLinearY(t)
-                        populated = true
+            while (j < size - 1) {
+                val arc = arcs[i][k]
+                if (t <= arc.time2) {
+                    if (arc.isLinear) {
+                        v[j] = arc.getLinearX(t)
+                        v[j + 1] = arc.getLinearY(t)
                     } else {
-                        arcs[i][k].setPoint(t)
-                        v[j] = arcs[i][k].calcX()
-                        v[j + 1] = arcs[i][k].calcY()
-                        populated = true
+                        arc.setPoint(t)
+                        v[j] = arc.calcX()
+                        v[j + 1] = arc.calcY()
                     }
+                    populated = true
                 }
                 j += 2
                 k++
@@ -143,29 +158,27 @@
 
     /** Get the differential which of the curves at point t */
     fun getSlope(time: Float, v: FloatArray) {
-        var t = time
-        if (t < arcs[0][0].time1) {
-            t = arcs[0][0].time1
-        } else if (t > arcs[arcs.size - 1][0].time2) {
-            t = arcs[arcs.size - 1][0].time2
-        }
+        val arcs = arcs
+        val t = time.fastCoerceIn(arcs[0][0].time1, arcs[arcs.size - 1][0].time2)
+        val size = v.size
+
         var populated = false
         // TODO: Consider passing the index from the caller to improve performance
         for (i in arcs.indices) {
             var j = 0
             var k = 0
-            while (j < v.size) {
-                if (t <= arcs[i][k].time2) {
-                    if (arcs[i][k].isLinear) {
-                        v[j] = arcs[i][k].getLinearDX()
-                        v[j + 1] = arcs[i][k].getLinearDY()
-                        populated = true
+            while (j < size - 1) {
+                val arc = arcs[i][k]
+                if (t <= arc.time2) {
+                    if (arc.isLinear) {
+                        v[j] = arc.linearDX
+                        v[j + 1] = arc.linearDY
                     } else {
-                        arcs[i][k].setPoint(t)
-                        v[j] = arcs[i][k].calcDX()
-                        v[j + 1] = arcs[i][k].calcDY()
-                        populated = true
+                        arc.setPoint(t)
+                        v[j] = arc.calcDX()
+                        v[j + 1] = arc.calcDY()
                     }
+                    populated = true
                 }
                 j += 2
                 k++
@@ -192,46 +205,51 @@
 
         private val lut: FloatArray
         private val oneOverDeltaTime: Float
-        private val ellipseA: Float
-        private val ellipseB: Float
-        private val ellipseCenterX: Float // also used to cache the slope in the unused center
-        private val ellipseCenterY: Float // also used to cache the slope in the unused center
         private val arcVelocity: Float
-        private val isVertical: Boolean
+        private val vertical: Float
 
-        val isLinear: Boolean
+        @JvmField internal val ellipseA: Float
+        @JvmField internal val ellipseB: Float
+
+        @JvmField internal val isLinear: Boolean
+
+        // also used to cache the slope in the unused center
+        @JvmField internal val ellipseCenterX: Float
+        // also used to cache the slope in the unused center
+        @JvmField internal val ellipseCenterY: Float
+
+        internal inline val linearDX: Float
+            get() = ellipseCenterX
+
+        internal inline val linearDY: Float
+            get() = ellipseCenterY
 
         init {
             val dx = x2 - x1
             val dy = y2 - y1
-            isVertical =
+            val isVertical =
                 when (mode) {
                     StartVertical -> true
                     UpArc -> dy < 0
                     DownArc -> dy > 0
                     else -> false
                 }
+            vertical = if (isVertical) -1.0f else 1.0f
             oneOverDeltaTime = 1 / (this.time2 - this.time1)
+            lut = FloatArray(LutSize)
 
-            var isLinear = false
-            if (StartLinear == mode) {
-                isLinear = true
-            }
+            var isLinear = mode == StartLinear
             if (isLinear || abs(dx) < Epsilon || abs(dy) < Epsilon) {
                 isLinear = true
                 arcDistance = hypot(dy, dx)
                 arcVelocity = arcDistance * oneOverDeltaTime
-                ellipseCenterX =
-                    dx / (this.time2 - this.time1) // cache the slope in the unused center
-                ellipseCenterY =
-                    dy / (this.time2 - this.time1) // cache the slope in the unused center
-                lut = FloatArray(101)
+                ellipseCenterX = dx * oneOverDeltaTime // cache the slope in the unused center
+                ellipseCenterY = dy * oneOverDeltaTime // cache the slope in the unused center
                 ellipseA = Float.NaN
                 ellipseB = Float.NaN
             } else {
-                lut = FloatArray(101)
-                ellipseA = dx * if (isVertical) -1 else 1
-                ellipseB = dy * if (isVertical) 1 else -1
+                ellipseA = dx * vertical
+                ellipseB = dy * -vertical
                 ellipseCenterX = if (isVertical) x2 else x1
                 ellipseCenterY = if (isVertical) y1 else y2
                 buildTable(x1, y1, x2, y2)
@@ -241,17 +259,21 @@
         }
 
         fun setPoint(time: Float) {
-            val percent = (if (isVertical) time2 - time else time - time1) * oneOverDeltaTime
-            val angle = PI.toFloat() * 0.5f * lookup(percent)
+            val angle = calcAngle(time)
             tmpSinAngle = sin(angle)
             tmpCosAngle = cos(angle)
         }
 
-        fun calcX(): Float {
+        private inline fun calcAngle(time: Float): Float {
+            val percent = (if (vertical == -1.0f) time2 - time else time - time1) * oneOverDeltaTime
+            return HalfPi * lookup(percent)
+        }
+
+        inline fun calcX(): Float {
             return ellipseCenterX + ellipseA * tmpSinAngle
         }
 
-        fun calcY(): Float {
+        inline fun calcY(): Float {
             return ellipseCenterY + ellipseB * tmpCosAngle
         }
 
@@ -259,14 +281,14 @@
             val vx = ellipseA * tmpCosAngle
             val vy = -ellipseB * tmpSinAngle
             val norm = arcVelocity / hypot(vx, vy)
-            return if (isVertical) -vx * norm else vx * norm
+            return vx * vertical * norm
         }
 
         fun calcDY(): Float {
             val vx = ellipseA * tmpCosAngle
             val vy = -ellipseB * tmpSinAngle
             val norm = arcVelocity / hypot(vx, vy)
-            return if (isVertical) -vy * norm else vy * norm
+            return vy * vertical * norm
         }
 
         fun getLinearX(time: Float): Float {
@@ -281,14 +303,6 @@
             return y1 + t * (y2 - y1)
         }
 
-        fun getLinearDX(): Float {
-            return ellipseCenterX
-        }
-
-        fun getLinearDY(): Float {
-            return ellipseCenterY
-        }
-
         private fun lookup(v: Float): Float {
             if (v <= 0) {
                 return 0.0f
@@ -296,40 +310,48 @@
             if (v >= 1) {
                 return 1.0f
             }
-            val pos = v * (lut.size - 1)
+            val pos = v * (LutSize - 1)
             val iv = pos.toInt()
             val off = pos - pos.toInt()
             return lut[iv] + off * (lut[iv + 1] - lut[iv])
         }
 
-        private fun buildTable(x1: Float, y1: Float, x2: Float, y2: Float) {
+        // Internal to prevent inlining from R8
+        @Suppress("MemberVisibilityCanBePrivate")
+        internal fun buildTable(x1: Float, y1: Float, x2: Float, y2: Float) {
             val a = x2 - x1
             val b = y1 - y2
             var lx = 0f
-            var ly = 0f
+            var ly = b // == b * cos(0), because we skip index 0 in the loops below
             var dist = 0f
-            for (i in ourPercent.indices) {
-                val angle = toRadians(90.0 * i / (ourPercent.size - 1)).toFloat()
+
+            val ourPercent = OurPercentCache
+            val lastIndex = ourPercent.size - 1
+            val lut = lut
+
+            for (i in 1..lastIndex) {
+                val angle = toRadians(90.0 * i / lastIndex).toFloat()
                 val s = sin(angle)
                 val c = cos(angle)
                 val px = a * s
                 val py = b * c
-                if (i > 0) {
-                    dist += hypot((px - lx), (py - ly))
-                    ourPercent[i] = dist
-                }
+                dist += hypot((px - lx), (py - ly)) // we don't want to compute and store dist
+                ourPercent[i] = dist // for i == 0
                 lx = px
                 ly = py
             }
+
             arcDistance = dist
-            for (i in ourPercent.indices) {
+            for (i in 1..lastIndex) {
                 ourPercent[i] /= dist
             }
+
+            val lutLastIndex = (LutSize - 1).toFloat()
             for (i in lut.indices) {
-                val pos = i / (lut.size - 1).toFloat()
+                val pos = i / lutLastIndex
                 val index = binarySearch(ourPercent, pos)
                 if (index >= 0) {
-                    lut[i] = index / (ourPercent.size - 1).toFloat()
+                    lut[i] = index / lutLastIndex
                 } else if (index == -1) {
                     lut[i] = 0f
                 } else {
@@ -337,42 +359,33 @@
                     val p2 = -index - 1
                     val ans =
                         (p1 + (pos - ourPercent[p1]) / (ourPercent[p2] - ourPercent[p1])) /
-                            (ourPercent.size - 1)
+                            lastIndex
                     lut[i] = ans
                 }
             }
         }
-
-        companion object {
-            private var _ourPercent: FloatArray? = null
-            private val ourPercent: FloatArray
-                get() {
-                    if (_ourPercent != null) {
-                        return _ourPercent!!
-                    }
-                    _ourPercent = FloatArray(91)
-                    return _ourPercent!!
-                }
-
-            private const val Epsilon = 0.001f
-        }
-    }
-
-    companion object {
-        const val ArcStartVertical = 1
-        const val ArcStartHorizontal = 2
-        const val ArcStartFlip = 3
-        const val ArcBelow = 4
-        const val ArcAbove = 5
-        const val ArcStartLinear = 0
-        private const val StartVertical = 1
-        private const val StartHorizontal = 2
-        private const val StartLinear = 3
-        private const val DownArc = 4
-        private const val UpArc = 5
     }
 }
 
+internal const val ArcSplineArcStartLinear = 0
+internal const val ArcSplineArcStartVertical = 1
+internal const val ArcSplineArcStartHorizontal = 2
+internal const val ArcSplineArcStartFlip = 3
+internal const val ArcSplineArcBelow = 4
+internal const val ArcSplineArcAbove = 5
+
+private const val StartVertical = 1
+private const val StartHorizontal = 2
+private const val StartLinear = 3
+private const val DownArc = 4
+private const val UpArc = 5
+private const val LutSize = 101
+
+private const val Epsilon = 0.001f
+private const val HalfPi = (PI * 0.5).toFloat()
+
+private val OurPercentCache: FloatArray = FloatArray(91)
+
 internal expect inline fun toRadians(value: Double): Double
 
 internal expect inline fun binarySearch(array: FloatArray, position: Float): Int
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/IntListExtension.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/IntListExtension.kt
deleted file mode 100644
index 5544fcb..0000000
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/IntListExtension.kt
+++ /dev/null
@@ -1,70 +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.animation.core
-
-import androidx.collection.IntList
-import kotlin.jvm.JvmOverloads
-
-// TODO(b/311454748): Move to :collection as public API once it's back on alpha. Also, add versions
-//  for LongList and FloatList.
-
-/**
- * [IntArray.binarySearch] For original documentation.
- *
- * Searches the list or the range of the list for the provided [element] using the binary search
- * algorithm. The list is expected to be sorted, otherwise the result is undefined.
- *
- * If the list contains multiple elements equal to the specified [element], there is no guarantee
- * which one will be found.
- *
- * @param element the to search for.
- * @param fromIndex the start of the range (inclusive) to search in, 0 by default.
- * @param toIndex the end of the range (exclusive) to search in, size of this list by default.
- * @return the index of the element, if it is contained in the list within the specified range;
- *   otherwise, the inverted insertion point `(-insertion point - 1)`. The insertion point is
- *   defined as the index at which the element should be inserted, so that the list (or the
- *   specified subrange of list) still remains sorted.
- * @throws IndexOutOfBoundsException if [fromIndex] is less than zero or [toIndex] is greater than
- *   the size of this list.
- * @throws IllegalArgumentException if [fromIndex] is greater than [toIndex].
- */
-@JvmOverloads
-internal fun IntList.binarySearch(element: Int, fromIndex: Int = 0, toIndex: Int = size): Int {
-    requirePrecondition(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" }
-    if (fromIndex < 0) {
-        throw IndexOutOfBoundsException("Index out of range: $fromIndex")
-    }
-    if (toIndex > size) {
-        throw IndexOutOfBoundsException("Index out of range: $toIndex")
-    }
-
-    var low = fromIndex
-    var high = toIndex - 1
-
-    while (low <= high) {
-        val mid = low + high ushr 1
-        val midVal = this[mid]
-        if (midVal < element) {
-            low = mid + 1
-        } else if (midVal > element) {
-            high = mid - 1
-        } else {
-            return mid // key found
-        }
-    }
-    return -(low + 1) // key not found.
-}
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
index b61ed67..1fc3a21 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
@@ -707,7 +707,7 @@
                     animation.animationSpecDuration =
                         ((1.0 - animation.start[0]) * totalDurationNanos).roundToLong()
                 }
-            } else {
+            } else if (totalDurationNanos != 0L) {
                 // seekTo() called with a fraction. If an animation is running, we can just wait
                 // for the animation to change the value. The fraction may not be the best way
                 // to advance a regular animation.
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
index d2e83ca..370a60d 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
@@ -22,6 +22,7 @@
 import androidx.collection.MutableIntObjectMap
 import androidx.compose.animation.core.AnimationConstants.DefaultDurationMillis
 import androidx.compose.animation.core.internal.JvmDefaultWithCompatibility
+import androidx.compose.ui.util.fastCoerceIn
 import kotlin.jvm.JvmInline
 import kotlin.math.min
 
@@ -183,7 +184,7 @@
  * [VectorizedDurationBasedAnimationSpec].
  */
 internal fun VectorizedDurationBasedAnimationSpec<*>.clampPlayTime(playTime: Long): Long {
-    return (playTime - delayMillis).coerceIn(0, durationMillis.toLong())
+    return (playTime - delayMillis).fastCoerceIn(0, durationMillis.toLong())
 }
 
 /**
@@ -260,7 +261,7 @@
                         VectorizedKeyframeSpecElementInfo(
                             vectorValue = valueEasing.first,
                             easing = valueEasing.second,
-                            arcMode = ArcMode.Companion.ArcLinear
+                            arcMode = ArcMode.ArcLinear
                         )
                 }
 
@@ -269,7 +270,7 @@
         durationMillis = durationMillis,
         delayMillis = delayMillis,
         defaultEasing = LinearEasing,
-        initialArcMode = ArcMode.Companion.ArcLinear
+        initialArcMode = ArcMode.ArcLinear
     )
 
     /**
@@ -302,7 +303,7 @@
             modes =
                 IntArray(timestamps.size) {
                     val mode = (keyframes[timestamps[it]]?.arcMode ?: initialArcMode)
-                    if (mode != ArcMode.Companion.ArcLinear) {
+                    if (mode != ArcMode.ArcLinear) {
                         requiresArcSpline = true
                     }
 
@@ -505,7 +506,6 @@
     }
 }
 
-@OptIn(ExperimentalAnimationSpecApi::class)
 internal data class VectorizedKeyframeSpecElementInfo(
     val vectorValue: V,
     val easing: Easing,
@@ -528,20 +528,20 @@
          * Interpolates using a quarter of an Ellipse where the curve is "above" the center of the
          * Ellipse.
          */
-        public val ArcAbove: ArcMode = ArcMode(ArcSpline.ArcAbove)
+        public val ArcAbove: ArcMode = ArcMode(ArcSplineArcAbove)
 
         /**
          * Interpolates using a quarter of an Ellipse where the curve is "below" the center of the
          * Ellipse.
          */
-        public val ArcBelow: ArcMode = ArcMode(ArcSpline.ArcBelow)
+        public val ArcBelow: ArcMode = ArcMode(ArcSplineArcBelow)
 
         /**
          * An [ArcMode] that forces linear interpolation.
          *
          * You'll likely only use this mode within a keyframe.
          */
-        public val ArcLinear: ArcMode = ArcMode(ArcSpline.ArcStartLinear)
+        public val ArcLinear: ArcMode = ArcMode(ArcSplineArcStartLinear)
     }
 }
 
@@ -560,10 +560,10 @@
         targetValue: V,
         initialVelocity: V
     ): V {
-        if (playTimeNanos < delayMillis * MillisToNanos) {
-            return initialValue
+        return if (playTimeNanos < delayMillis * MillisToNanos) {
+            initialValue
         } else {
-            return targetValue
+            targetValue
         }
     }
 
@@ -580,8 +580,6 @@
         get() = 0
 }
 
-private const val InfiniteIterations: Int = Int.MAX_VALUE
-
 /**
  * This animation takes another [VectorizedDurationBasedAnimationSpec] and plays it __infinite__
  * times.
@@ -742,10 +740,10 @@
         } else {
             val postOffsetPlayTimeNanos = playTimeNanos + initialOffsetNanos
             val repeatsCount = min(postOffsetPlayTimeNanos / durationNanos, iterations - 1L)
-            if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
-                return postOffsetPlayTimeNanos - repeatsCount * durationNanos
+            return if (repeatMode == RepeatMode.Restart || repeatsCount % 2 == 0L) {
+                postOffsetPlayTimeNanos - repeatsCount * durationNanos
             } else {
-                return (repeatsCount + 1) * durationNanos - postOffsetPlayTimeNanos
+                (repeatsCount + 1) * durationNanos - postOffsetPlayTimeNanos
             }
         }
     }
diff --git a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridContentPaddingTest.kt b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridContentPaddingTest.kt
index 50dcbe8..84a7799 100644
--- a/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridContentPaddingTest.kt
+++ b/compose/foundation/foundation/integration-tests/lazy-tests/src/androidTest/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridContentPaddingTest.kt
@@ -314,4 +314,33 @@
 
         rule.onNodeWithTag(LazyStaggeredGrid).assertMainAxisSizeIsEqualTo(itemSizeDp * 6)
     }
+
+    @Test
+    fun afterContentPaddingWithSmallScrolls() {
+        state = LazyStaggeredGridState(initialFirstVisibleItemIndex = 0)
+        rule.setContent {
+            Box(Modifier.axisSize(itemSizeDp * 2, itemSizeDp * 4)) {
+                LazyStaggeredGrid(
+                    lanes = 2,
+                    modifier = Modifier.testTag(LazyStaggeredGrid),
+                    contentPadding = PaddingValues(afterContent = itemSizeDp / 2),
+                    state = state
+                ) {
+                    items(20, key = { it }) {
+                        val size = if (it == 0 || it == 19) itemSizeDp / 2 else itemSizeDp * 2
+                        Spacer(Modifier.mainAxisSize(size).testTag("$it").debugBorder())
+                    }
+                }
+            }
+        }
+
+        // scroll to the end
+        state.scrollBy(itemSizeDp * 30)
+
+        state.scrollBy(-5.dp)
+
+        state.scrollBy(itemSizeDp / 2)
+
+        rule.onNodeWithTag("19").assertMainAxisStartPositionInRootIsEqualTo(itemSizeDp * 3f)
+    }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasureResult.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasureResult.kt
index d070bc0..89174a1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasureResult.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasureResult.kt
@@ -168,6 +168,7 @@
         ) {
             return null
         }
+        val mainAxisMax = viewportEndOffset - afterContentPadding
         visibleItemsInfo.fastForEach {
             // non scrollable items require special handling.
             if (
@@ -192,7 +193,7 @@
                 if (!canApply) return null
             }
             // item is partially visible at the bottom.
-            if (it.mainAxisOffset + it.mainAxisSizeWithSpacings >= viewportEndOffset) {
+            if (it.mainAxisOffset + it.mainAxisSizeWithSpacings >= mainAxisMax) {
                 val canApply =
                     if (delta < 0) { // scrolling forward
                         it.mainAxisOffset + it.mainAxisSizeWithSpacings - viewportEndOffset > -delta
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 887b901..649ee6f 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -994,16 +994,22 @@
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getXSmallSquareShape();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonLocalContentColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonLocalContentColors();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long largeContainerSize(optional int widthOption);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long mediumContainerSize(optional int widthOption);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconButtonLocalContentColorBorder(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonLocalContentColors();
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonLocalContentColorBorder(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonLocalContentColors();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonShapes shapes(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape checkedShape);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long smallContainerSize(optional int widthOption);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long xLargeContainerSize(optional int widthOption);
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 887b901..649ee6f 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -994,16 +994,22 @@
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getXSmallSquareShape();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors iconButtonLocalContentColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors iconToggleButtonLocalContentColors();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long largeContainerSize(optional int widthOption);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long mediumContainerSize(optional int widthOption);
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke outlinedIconButtonBorder(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconButtonLocalContentColorBorder(boolean enabled);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonColors outlinedIconButtonLocalContentColors();
     method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonBorder(boolean enabled, boolean checked);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long checkedContainerColor, optional long checkedContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.BorderStroke? outlinedIconToggleButtonLocalContentColorBorder(boolean enabled, boolean checked);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.IconToggleButtonColors outlinedIconToggleButtonLocalContentColors();
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @androidx.compose.runtime.Composable public androidx.compose.material3.IconButtonShapes shapes(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape checkedShape);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long smallContainerSize(optional int widthOption);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3ExpressiveApi public long xLargeContainerSize(optional int widthOption);
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/IconButtonDemos.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/IconButtonDemos.kt
index 1a0178d..c4350f2 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/IconButtonDemos.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/IconButtonDemos.kt
@@ -21,6 +21,7 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
@@ -34,8 +35,10 @@
 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.FilledIconButton
 import androidx.compose.material3.FilledIconToggleButton
+import androidx.compose.material3.FilledTonalIconButton
 import androidx.compose.material3.FilledTonalIconToggleButton
 import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
 import androidx.compose.material3.IconButtonDefaults
 import androidx.compose.material3.IconButtonDefaults.IconButtonWidthOption.Companion.Narrow
 import androidx.compose.material3.IconButtonDefaults.IconButtonWidthOption.Companion.Wide
@@ -321,10 +324,7 @@
             // xsmall round icon button
             OutlinedIconButton(
                 onClick = { /* doSomething() */ },
-                modifier =
-                    Modifier
-                        // .minimumInteractiveComponentSize()
-                        .size(IconButtonDefaults.xSmallContainerSize()),
+                modifier = Modifier.size(IconButtonDefaults.xSmallContainerSize()),
                 shape = IconButtonDefaults.xSmallRoundShape
             ) {
                 Icon(
@@ -337,10 +337,7 @@
             // Small round icon button
             OutlinedIconButton(
                 onClick = { /* doSomething() */ },
-                modifier =
-                    Modifier
-                        // .minimumInteractiveComponentSize()
-                        .size(IconButtonDefaults.smallContainerSize()),
+                modifier = Modifier.size(IconButtonDefaults.smallContainerSize()),
                 shape = IconButtonDefaults.smallRoundShape
             ) {
                 Icon(
@@ -487,11 +484,11 @@
 
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
-fun IconToggleButtonsDemo() {
+fun IconButtonAndToggleButtonsDemo() {
     Column {
         val rowScrollState = rememberScrollState()
         val padding = 16.dp
-        // unselected round row
+
         Row(
             modifier =
                 Modifier.height(150.dp)
@@ -506,7 +503,35 @@
             Text("Outline")
             Text("Standard")
         }
-        // unselected round row
+        // icon buttons
+        Row(
+            modifier =
+                Modifier.height(150.dp)
+                    .horizontalScroll(rowScrollState)
+                    .padding(horizontal = padding),
+            horizontalArrangement = Arrangement.spacedBy(padding),
+            verticalAlignment = Alignment.CenterVertically
+        ) {
+            Spacer(Modifier.width(76.dp))
+
+            FilledIconButton(onClick = {}) {
+                Icon(Icons.Outlined.Edit, contentDescription = "Localized description")
+            }
+
+            FilledTonalIconButton(onClick = {}) {
+                Icon(Icons.Outlined.Edit, contentDescription = "Localized description")
+            }
+
+            OutlinedIconButton(onClick = {}) {
+                Icon(Icons.Outlined.Edit, contentDescription = "Localized description")
+            }
+
+            IconButton(onClick = {}) {
+                Icon(Icons.Outlined.Edit, contentDescription = "Localized description")
+            }
+        }
+
+        // unselected icon toggle buttons
         Row(
             modifier =
                 Modifier.height(150.dp)
@@ -517,7 +542,15 @@
         ) {
             var checked by remember { mutableStateOf(false) }
 
-            Text("Unselected")
+            Text(
+                text =
+                    if (!checked) {
+                        "Unselected"
+                    } else {
+                        "Selected"
+                    },
+                modifier = Modifier.defaultMinSize(minWidth = 76.dp),
+            )
 
             FilledIconToggleButton(
                 checked = checked,
@@ -572,7 +605,7 @@
             }
         }
 
-        // unselected round row
+        // selected icon toggle buttons
         Row(
             modifier =
                 Modifier.height(150.dp)
@@ -582,7 +615,17 @@
             verticalAlignment = Alignment.CenterVertically
         ) {
             var checked by remember { mutableStateOf(true) }
-            Text("Selected")
+
+            Text(
+                text =
+                    if (!checked) {
+                        "Unselected"
+                    } else {
+                        "Selected"
+                    },
+                modifier = Modifier.defaultMinSize(minWidth = 76.dp)
+            )
+
             FilledIconToggleButton(
                 checked = checked,
                 onCheckedChange = { checked = it },
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
index 66e8991..ee0c4f3 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
@@ -34,7 +34,9 @@
                 listOf(
                     ComposableDemo("Sizes") { IconButtonMeasurementsDemo() },
                     ComposableDemo("Corners") { IconButtonCornerRadiusDemo() },
-                    ComposableDemo("Icon toggle buttons") { IconToggleButtonsDemo() },
+                    ComposableDemo("Icon button & icon toggle buttons") {
+                        IconButtonAndToggleButtonsDemo()
+                    },
                 )
             ),
             DemoCategory(
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AlertDialogTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AlertDialogTest.kt
index 0c8bf40..0bd5601 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AlertDialogTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/AlertDialogTest.kt
@@ -24,7 +24,6 @@
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
-import androidx.compose.material3.tokens.TextButtonTokens
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
@@ -91,7 +90,9 @@
                     TextButton(onClick = { /* doSomething() */ }) {
                         Text("Confirm")
                         buttonContentColor = LocalContentColor.current
-                        expectedButtonContentColor = TextButtonTokens.LabelColor.value
+                        // TODO change this back to the TextButtonTokens.LabelColor once the tokens
+                        // are updated
+                        expectedButtonContentColor = MaterialTheme.colorScheme.primary
                     }
                 },
                 containerColor = Color.Yellow,
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ButtonTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ButtonTest.kt
index e7f9bd2..9b52bf3 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ButtonTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/ButtonTest.kt
@@ -415,7 +415,9 @@
                 .isEqualTo(
                     ButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = TextButtonTokens.LabelColor.value,
+                        // TODO change this back to the TextButtonTokens.LabelColor once the tokens
+                        // are updated
+                        contentColor = MaterialTheme.colorScheme.primary,
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
                             TextButtonTokens.DisabledLabelColor.value.copy(
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
index 7a64ed6..1cf7f4b 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
@@ -32,9 +32,9 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.material3.tokens.ExtendedFabPrimaryTokens
-import androidx.compose.material3.tokens.FabPrimaryLargeTokens
-import androidx.compose.material3.tokens.FabPrimarySmallTokens
-import androidx.compose.material3.tokens.FabPrimaryTokens
+import androidx.compose.material3.tokens.FabBaselineTokens
+import androidx.compose.material3.tokens.FabLargeTokens
+import androidx.compose.material3.tokens.FabSmallTokens
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
@@ -128,12 +128,12 @@
                     Icon(Icons.Filled.Favorite, null, modifier = Modifier.testTag("icon"))
                 }
             }
-            .assertIsSquareWithSize(FabPrimaryTokens.ContainerHeight)
+            .assertIsSquareWithSize(FabBaselineTokens.ContainerHeight)
 
         rule
             .onNodeWithTag("icon", useUnmergedTree = true)
-            .assertHeightIsEqualTo(FabPrimaryTokens.IconSize)
-            .assertWidthIsEqualTo(FabPrimaryTokens.IconSize)
+            .assertHeightIsEqualTo(FabBaselineTokens.IconSize)
+            .assertWidthIsEqualTo(FabBaselineTokens.IconSize)
     }
 
     @OptIn(ExperimentalMaterial3Api::class)
@@ -148,12 +148,12 @@
                 }
             }
             // Expecting the size to be equal to the token size.
-            .assertIsSquareWithSize(FabPrimarySmallTokens.ContainerHeight)
+            .assertIsSquareWithSize(FabSmallTokens.ContainerHeight)
 
         rule
             .onNodeWithTag("icon", useUnmergedTree = true)
-            .assertHeightIsEqualTo(FabPrimarySmallTokens.IconSize)
-            .assertWidthIsEqualTo(FabPrimarySmallTokens.IconSize)
+            .assertHeightIsEqualTo(FabSmallTokens.IconSize)
+            .assertWidthIsEqualTo(FabSmallTokens.IconSize)
     }
 
     @OptIn(ExperimentalMaterial3Api::class)
@@ -184,7 +184,7 @@
                     )
                 }
             }
-            .assertIsSquareWithSize(FabPrimaryLargeTokens.ContainerHeight)
+            .assertIsSquareWithSize(FabLargeTokens.ContainerHeight)
 
         rule
             .onNodeWithTag("icon", useUnmergedTree = true)
@@ -206,7 +206,7 @@
         rule
             .onNodeWithTag("FAB")
             .assertHeightIsEqualTo(ExtendedFabPrimaryTokens.ContainerHeight)
-            .assertWidthIsAtLeast(FabPrimaryTokens.ContainerHeight)
+            .assertWidthIsAtLeast(FabBaselineTokens.ContainerHeight)
     }
 
     @Test
@@ -468,7 +468,7 @@
             )
         }
 
-        rule.onNodeWithTag("FAB").assertIsSquareWithSize(FabPrimaryTokens.ContainerHeight)
+        rule.onNodeWithTag("FAB").assertIsSquareWithSize(FabBaselineTokens.ContainerHeight)
 
         rule
             .onNodeWithTag("icon", useUnmergedTree = true)
@@ -504,9 +504,9 @@
 
         rule
             .onNodeWithTag("FAB")
-            .assertIsSquareWithSize(FabPrimaryTokens.ContainerHeight)
-            .assertHeightIsEqualTo(FabPrimaryTokens.ContainerHeight)
-            .assertWidthIsEqualTo(FabPrimaryTokens.ContainerWidth)
+            .assertIsSquareWithSize(FabBaselineTokens.ContainerHeight)
+            .assertHeightIsEqualTo(FabBaselineTokens.ContainerHeight)
+            .assertWidthIsEqualTo(FabBaselineTokens.ContainerWidth)
     }
 
     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/IconButtonTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/IconButtonTest.kt
index 647b1cf..5eaa44a 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/IconButtonTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/IconButtonTest.kt
@@ -306,10 +306,10 @@
     }
 
     @Test
-    fun iconButton_defaultColors() {
+    fun iconButton_defaultLocalContentColors() {
         rule.setMaterialContent(lightColorScheme()) {
             CompositionLocalProvider(LocalContentColor provides Color.Blue) {
-                Truth.assertThat(IconButtonDefaults.iconButtonColors())
+                Truth.assertThat(IconButtonDefaults.iconButtonLocalContentColors())
                     .isEqualTo(
                         IconButtonColors(
                             containerColor = Color.Transparent,
@@ -324,15 +324,35 @@
     }
 
     @Test
+    fun iconButton_defaultColors() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Truth.assertThat(IconButtonDefaults.iconButtonColors())
+                .isEqualTo(
+                    IconButtonColors(
+                        containerColor = Color.Transparent,
+                        contentColor = StandardIconButtonTokens.Color.value,
+                        disabledContainerColor = Color.Transparent,
+                        disabledContentColor =
+                            StandardIconButtonTokens.DisabledColor.value.copy(
+                                alpha = StandardIconButtonTokens.DisabledOpacity
+                            )
+                    )
+                )
+        }
+    }
+
+    @Test
     fun iconButtonColors_localContentColor() {
         rule.setMaterialContent(lightColorScheme()) {
             CompositionLocalProvider(LocalContentColor provides Color.Blue) {
-                val colors = IconButtonDefaults.iconButtonColors()
+                val colors = IconButtonDefaults.iconButtonLocalContentColors()
                 assert(colors.contentColor == Color.Blue)
             }
 
             CompositionLocalProvider(LocalContentColor provides Color.Red) {
-                val colors = IconButtonDefaults.iconButtonColors(containerColor = Color.Green)
+                val colors =
+                    IconButtonDefaults.iconButtonLocalContentColors()
+                        .copy(containerColor = Color.Green)
                 assert(colors.containerColor == Color.Green)
                 assert(colors.contentColor == Color.Red)
             }
@@ -340,10 +360,10 @@
     }
 
     @Test
-    fun iconButtonColors_customValues() {
+    fun iconButtonColors_customValues_useLocalContentColor() {
         rule.setMaterialContent(lightColorScheme()) {
             CompositionLocalProvider(LocalContentColor provides Color.Blue) {
-                val colors = IconButtonDefaults.iconButtonColors()
+                val colors = IconButtonDefaults.iconButtonLocalContentColors()
                 assert(colors.contentColor == Color.Blue)
                 assert(
                     colors.disabledContentColor ==
@@ -368,6 +388,25 @@
     }
 
     @Test
+    fun iconButtonColors_customValues() {
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalContentColor provides Color.Red) {
+                val colors =
+                    IconButtonDefaults.iconButtonColors(
+                        containerColor = Color.Blue,
+                        contentColor = Color.Green
+                    )
+                assert(colors.containerColor == Color.Blue)
+                assert(colors.contentColor == Color.Green)
+                assert(
+                    colors.disabledContentColor ==
+                        Color.Green.copy(StandardIconButtonTokens.DisabledOpacity)
+                )
+            }
+        }
+    }
+
+    @Test
     fun iconButtonColors_copy() {
         rule.setMaterialContent(lightColorScheme()) {
             val colors = IconButtonDefaults.iconButtonColors().copy()
@@ -501,10 +540,10 @@
         }
 
     @Test
-    fun iconToggleButton_defaultColors() {
+    fun iconToggleButton_defaultLocalContentColors() {
         rule.setMaterialContent(lightColorScheme()) {
             val localContentColor = LocalContentColor.current
-            Truth.assertThat(IconButtonDefaults.iconToggleButtonColors())
+            Truth.assertThat(IconButtonDefaults.iconToggleButtonLocalContentColors())
                 .isEqualTo(
                     IconToggleButtonColors(
                         containerColor = Color.Transparent,
@@ -522,6 +561,26 @@
     }
 
     @Test
+    fun iconToggleButton_defaultColors() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Truth.assertThat(IconButtonDefaults.iconToggleButtonColors())
+                .isEqualTo(
+                    IconToggleButtonColors(
+                        containerColor = Color.Transparent,
+                        contentColor = StandardIconButtonTokens.UnselectedColor.value,
+                        disabledContainerColor = Color.Transparent,
+                        disabledContentColor =
+                            StandardIconButtonTokens.DisabledColor.value.copy(
+                                alpha = StandardIconButtonTokens.DisabledOpacity
+                            ),
+                        checkedContainerColor = Color.Transparent,
+                        checkedContentColor = StandardIconButtonTokens.SelectedColor.value
+                    )
+                )
+        }
+    }
+
+    @Test
     fun filledIconButton_xsmall_visualBounds() {
         val expectedWidth =
             with(rule.density) { IconButtonDefaults.xSmallContainerSize().width.roundToPx() }
@@ -1136,23 +1195,6 @@
     }
 
     @Test
-    fun outlinedIconButton_defaultColors() {
-        rule.setMaterialContent(lightColorScheme()) {
-            val localContentColor = LocalContentColor.current
-            Truth.assertThat(IconButtonDefaults.outlinedIconButtonColors())
-                .isEqualTo(
-                    IconButtonColors(
-                        containerColor = Color.Transparent,
-                        contentColor = localContentColor,
-                        disabledContainerColor = Color.Transparent,
-                        disabledContentColor =
-                            localContentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
-                    )
-                )
-        }
-    }
-
-    @Test
     fun outlinedIconToggleButton_size() {
         rule
             .setMaterialContentForSizeAssertions {
@@ -1260,13 +1302,74 @@
     }
 
     @Test
-    fun outlinedIconToggleButton_defaultColors() {
+    fun outlinedIconButton_defaultLocalContentColors() {
         rule.setMaterialContent(lightColorScheme()) {
             val localContentColor = LocalContentColor.current
+            Truth.assertThat(IconButtonDefaults.outlinedIconButtonLocalContentColors())
+                .isEqualTo(
+                    IconButtonColors(
+                        containerColor = Color.Transparent,
+                        contentColor = localContentColor,
+                        disabledContainerColor = Color.Transparent,
+                        disabledContentColor =
+                            localContentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun outlinedIconButton_defaultColors() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Truth.assertThat(IconButtonDefaults.outlinedIconButtonColors())
+                .isEqualTo(
+                    IconButtonColors(
+                        containerColor = Color.Transparent,
+                        contentColor = OutlinedIconButtonTokens.Color.value,
+                        disabledContainerColor = Color.Transparent,
+                        disabledContentColor =
+                            OutlinedIconButtonTokens.DisabledColor.value.copy(
+                                alpha = OutlinedIconButtonTokens.DisabledOpacity
+                            )
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun outlinedIconToggleButton_defaultColors() {
+        rule.setMaterialContent(lightColorScheme()) {
             Truth.assertThat(IconButtonDefaults.outlinedIconToggleButtonColors())
                 .isEqualTo(
                     IconToggleButtonColors(
                         containerColor = Color.Transparent,
+                        contentColor = OutlinedIconButtonTokens.UnselectedColor.value,
+                        disabledContainerColor = Color.Transparent,
+                        disabledContentColor =
+                            OutlinedIconButtonTokens.DisabledColor.value.copy(
+                                alpha = OutlinedIconButtonTokens.DisabledOpacity
+                            ),
+                        checkedContainerColor =
+                            OutlinedIconButtonTokens.SelectedContainerColor.value,
+                        checkedContentColor = OutlinedIconButtonTokens.SelectedColor.value
+                    )
+                )
+        }
+    }
+
+    @Test
+    fun outlinedIconToggleButton_defaultLocalContentColors_reuse() {
+        rule.setMaterialContent(lightColorScheme()) {
+            val localContentColor = LocalContentColor.current
+            Truth.assertThat(MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonColorsCached)
+                .isNull()
+            val colors = IconButtonDefaults.outlinedIconToggleButtonLocalContentColors()
+            Truth.assertThat(MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonColorsCached)
+                .isNotNull()
+            Truth.assertThat(colors)
+                .isEqualTo(
+                    IconToggleButtonColors(
+                        containerColor = Color.Transparent,
                         contentColor = localContentColor,
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
@@ -1295,7 +1398,7 @@
                 .isEqualTo(
                     IconToggleButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = localContentColor,
+                        contentColor = OutlinedIconButtonTokens.UnselectedColor.value,
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
                             localContentColor.copy(
@@ -1303,8 +1406,7 @@
                             ),
                         checkedContainerColor =
                             OutlinedIconButtonTokens.SelectedContainerColor.value,
-                        checkedContentColor =
-                            contentColorFor(OutlinedIconButtonTokens.SelectedContainerColor.value)
+                        checkedContentColor = OutlinedIconButtonTokens.SelectedColor.value
                     )
                 )
         }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
index f712ed9..9193761 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
@@ -45,7 +45,7 @@
 import androidx.compose.material3.internal.ProvideContentColorTextStyle
 import androidx.compose.material3.internal.systemBarsForVisualComponents
 import androidx.compose.material3.tokens.BottomAppBarTokens
-import androidx.compose.material3.tokens.FabSecondaryTokens
+import androidx.compose.material3.tokens.FabSecondaryContainerTokens
 import androidx.compose.material3.tokens.MotionSchemeKeyTokens
 import androidx.compose.material3.tokens.TopAppBarLargeTokens
 import androidx.compose.material3.tokens.TopAppBarMediumTokens
@@ -1971,7 +1971,7 @@
 
     /** The color of a [BottomAppBar]'s [FloatingActionButton] */
     val bottomAppBarFabColor: Color
-        @Composable get() = FabSecondaryTokens.ContainerColor.value
+        @Composable get() = FabSecondaryContainerTokens.ContainerColor.value
 
     val HorizontalArrangement =
         Arrangement.spacedBy(32.dp, Alignment.CenterHorizontally) // TODO tokens
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
index 8ca5c0f..1473429 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
@@ -35,6 +35,7 @@
 import androidx.compose.material3.internal.animateElevation
 import androidx.compose.material3.tokens.BaselineButtonTokens
 import androidx.compose.material3.tokens.ButtonSmallTokens
+import androidx.compose.material3.tokens.ColorSchemeKeyTokens
 import androidx.compose.material3.tokens.ElevatedButtonTokens
 import androidx.compose.material3.tokens.FilledButtonTokens
 import androidx.compose.material3.tokens.FilledTonalButtonTokens
@@ -805,7 +806,8 @@
             return defaultTextButtonColorsCached
                 ?: ButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = fromToken(TextButtonTokens.LabelColor),
+                        // TODO replace with the token value once it's corrected
+                        contentColor = fromToken(ColorSchemeKeyTokens.Primary),
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
                             fromToken(TextButtonTokens.DisabledLabelColor)
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
index e3f0cc8..e4208ec 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButton.kt
@@ -43,10 +43,16 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.material3.internal.ProvideContentColorTextStyle
 import androidx.compose.material3.internal.animateElevation
+import androidx.compose.material3.tokens.ElevationTokens
+import androidx.compose.material3.tokens.ExtendedFabLargeTokens
+import androidx.compose.material3.tokens.ExtendedFabMediumTokens
 import androidx.compose.material3.tokens.ExtendedFabPrimaryTokens
-import androidx.compose.material3.tokens.FabPrimaryLargeTokens
-import androidx.compose.material3.tokens.FabPrimarySmallTokens
-import androidx.compose.material3.tokens.FabPrimaryTokens
+import androidx.compose.material3.tokens.ExtendedFabSmallTokens
+import androidx.compose.material3.tokens.FabBaselineTokens
+import androidx.compose.material3.tokens.FabLargeTokens
+import androidx.compose.material3.tokens.FabMediumTokens
+import androidx.compose.material3.tokens.FabPrimaryContainerTokens
+import androidx.compose.material3.tokens.FabSmallTokens
 import androidx.compose.material3.tokens.MotionSchemeKeyTokens
 import androidx.compose.material3.tokens.TypographyKeyTokens
 import androidx.compose.runtime.Composable
@@ -130,8 +136,8 @@
     FloatingActionButton(
         onClick,
         ExtendedFabPrimaryTokens.LabelTextFont.value,
-        FabPrimaryTokens.ContainerWidth,
-        FabPrimaryTokens.ContainerHeight,
+        FabBaselineTokens.ContainerWidth,
+        FabBaselineTokens.ContainerHeight,
         modifier,
         shape,
         containerColor,
@@ -229,8 +235,8 @@
         onClick = onClick,
         modifier =
             modifier.sizeIn(
-                minWidth = FabPrimarySmallTokens.ContainerWidth,
-                minHeight = FabPrimarySmallTokens.ContainerHeight,
+                minWidth = FabSmallTokens.ContainerWidth,
+                minHeight = FabSmallTokens.ContainerHeight,
             ),
         shape = shape,
         containerColor = containerColor,
@@ -285,10 +291,9 @@
     FloatingActionButton(
         onClick = onClick,
         modifier =
-            // TODO: update sizes to use tokens
             modifier.sizeIn(
-                minWidth = 80.dp,
-                minHeight = 80.dp,
+                minWidth = FabMediumTokens.ContainerWidth,
+                minHeight = FabMediumTokens.ContainerHeight,
             ),
         shape = shape,
         containerColor = containerColor,
@@ -346,8 +351,8 @@
         onClick = onClick,
         modifier =
             modifier.sizeIn(
-                minWidth = FabPrimaryLargeTokens.ContainerWidth,
-                minHeight = FabPrimaryLargeTokens.ContainerHeight,
+                minWidth = FabLargeTokens.ContainerWidth,
+                minHeight = FabLargeTokens.ContainerHeight,
             ),
         shape = shape,
         containerColor = containerColor,
@@ -412,7 +417,11 @@
         interactionSource = interactionSource,
     ) {
         Row(
-            modifier = Modifier.padding(horizontal = SmallExtendedFabHorizontalPadding),
+            modifier =
+                Modifier.padding(
+                    start = SmallExtendedFabPaddingStart,
+                    end = SmallExtendedFabPaddingEnd
+                ),
             horizontalArrangement = Arrangement.Center,
             verticalAlignment = Alignment.CenterVertically,
             content = content,
@@ -474,7 +483,11 @@
         interactionSource = interactionSource,
     ) {
         Row(
-            modifier = Modifier.padding(horizontal = MediumExtendedFabHorizontalPadding),
+            modifier =
+                Modifier.padding(
+                    start = MediumExtendedFabPaddingStart,
+                    end = MediumExtendedFabPaddingEnd
+                ),
             horizontalArrangement = Arrangement.Center,
             verticalAlignment = Alignment.CenterVertically,
             content = content,
@@ -536,7 +549,11 @@
         interactionSource = interactionSource,
     ) {
         Row(
-            modifier = Modifier.padding(horizontal = LargeExtendedFabHorizontalPadding),
+            modifier =
+                Modifier.padding(
+                    start = LargeExtendedFabPaddingStart,
+                    end = LargeExtendedFabPaddingEnd
+                ),
             horizontalArrangement = Arrangement.Center,
             verticalAlignment = Alignment.CenterVertically,
             content = content,
@@ -662,7 +679,8 @@
         textStyle = SmallExtendedFabTextStyle.value,
         minWidth = SmallExtendedFabMinimumWidth,
         minHeight = SmallExtendedFabMinimumHeight,
-        horizontalPadding = SmallExtendedFabHorizontalPadding,
+        startPadding = SmallExtendedFabPaddingStart,
+        endPadding = SmallExtendedFabPaddingEnd,
         iconPadding = SmallExtendedFabIconPadding,
         modifier = modifier,
         expanded = expanded,
@@ -729,7 +747,8 @@
         textStyle = MediumExtendedFabTextStyle.value,
         minWidth = MediumExtendedFabMinimumWidth,
         minHeight = MediumExtendedFabMinimumHeight,
-        horizontalPadding = MediumExtendedFabHorizontalPadding,
+        startPadding = MediumExtendedFabPaddingStart,
+        endPadding = MediumExtendedFabPaddingEnd,
         iconPadding = MediumExtendedFabIconPadding,
         modifier = modifier,
         expanded = expanded,
@@ -796,7 +815,8 @@
         textStyle = LargeExtendedFabTextStyle.value,
         minWidth = LargeExtendedFabMinimumWidth,
         minHeight = LargeExtendedFabMinimumHeight,
-        horizontalPadding = LargeExtendedFabHorizontalPadding,
+        startPadding = LargeExtendedFabPaddingStart,
+        endPadding = LargeExtendedFabPaddingEnd,
         iconPadding = LargeExtendedFabIconPadding,
         modifier = modifier,
         expanded = expanded,
@@ -877,7 +897,7 @@
                             if (expanded) {
                                 ExtendedFabMinimumWidth
                             } else {
-                                FabPrimaryTokens.ContainerWidth
+                                FabBaselineTokens.ContainerWidth
                             }
                     )
                     .padding(start = startPadding, end = endPadding),
@@ -907,7 +927,8 @@
     textStyle: TextStyle,
     minWidth: Dp,
     minHeight: Dp,
-    horizontalPadding: Dp,
+    startPadding: Dp,
+    endPadding: Dp,
     iconPadding: Dp,
     modifier: Modifier = Modifier,
     expanded: Boolean = true,
@@ -947,7 +968,7 @@
                         layout(width, placeable.height) { placeable.place(0, 0) }
                     }
                     .sizeIn(minWidth = minWidth, minHeight = minHeight)
-                    .padding(horizontal = horizontalPadding),
+                    .padding(start = startPadding, end = endPadding),
             verticalAlignment = Alignment.CenterVertically,
         ) {
             icon()
@@ -978,18 +999,18 @@
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalMaterial3ExpressiveApi
     @ExperimentalMaterial3ExpressiveApi
-    val MediumIconSize = 28.dp // TODO: update to use token
+    val MediumIconSize = FabMediumTokens.IconSize
 
     /** The recommended size of the icon inside a [LargeFloatingActionButton]. */
-    val LargeIconSize = FabPrimaryLargeTokens.IconSize
+    val LargeIconSize = 36.dp // TODO: FabLargeTokens.IconSize is incorrect
 
     /** Default shape for a floating action button. */
     val shape: Shape
-        @Composable get() = FabPrimaryTokens.ContainerShape.value
+        @Composable get() = FabBaselineTokens.ContainerShape.value
 
     /** Default shape for a small floating action button. */
     val smallShape: Shape
-        @Composable get() = FabPrimarySmallTokens.ContainerShape.value
+        @Composable get() = FabSmallTokens.ContainerShape.value
 
     /** Default shape for a medium floating action button. */
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -1000,7 +1021,7 @@
 
     /** Default shape for a large floating action button. */
     val largeShape: Shape
-        @Composable get() = FabPrimaryLargeTokens.ContainerShape.value
+        @Composable get() = FabLargeTokens.ContainerShape.value
 
     /** Default shape for an extended floating action button. */
     val extendedFabShape: Shape
@@ -1011,7 +1032,7 @@
     @get:ExperimentalMaterial3ExpressiveApi
     @ExperimentalMaterial3ExpressiveApi
     val smallExtendedFabShape: Shape
-        @Composable get() = ShapeDefaults.Large // TODO: update to use token
+        @Composable get() = ExtendedFabSmallTokens.ContainerShape.value
 
     /** Default shape for a medium extended floating action button. */
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
@@ -1025,11 +1046,11 @@
     @get:ExperimentalMaterial3ExpressiveApi
     @ExperimentalMaterial3ExpressiveApi
     val largeExtendedFabShape: Shape
-        @Composable get() = ShapeDefaults.ExtraLarge // TODO: update to use token
+        @Composable get() = ExtendedFabLargeTokens.ContainerShape.value
 
     /** Default container color for a floating action button. */
     val containerColor: Color
-        @Composable get() = FabPrimaryTokens.ContainerColor.value
+        @Composable get() = FabPrimaryContainerTokens.ContainerColor.value
 
     /**
      * Creates a [FloatingActionButtonElevation] that represents the elevation of a
@@ -1044,10 +1065,10 @@
      */
     @Composable
     fun elevation(
-        defaultElevation: Dp = FabPrimaryTokens.ContainerElevation,
-        pressedElevation: Dp = FabPrimaryTokens.PressedContainerElevation,
-        focusedElevation: Dp = FabPrimaryTokens.FocusContainerElevation,
-        hoveredElevation: Dp = FabPrimaryTokens.HoverContainerElevation,
+        defaultElevation: Dp = FabPrimaryContainerTokens.ContainerElevation,
+        pressedElevation: Dp = FabPrimaryContainerTokens.PressedContainerElevation,
+        focusedElevation: Dp = FabPrimaryContainerTokens.FocusedContainerElevation,
+        hoveredElevation: Dp = FabPrimaryContainerTokens.HoveredContainerElevation,
     ): FloatingActionButtonElevation =
         FloatingActionButtonElevation(
             defaultElevation = defaultElevation,
@@ -1068,10 +1089,10 @@
      */
     @Composable
     fun loweredElevation(
-        defaultElevation: Dp = FabPrimaryTokens.LoweredContainerElevation,
-        pressedElevation: Dp = FabPrimaryTokens.LoweredPressedContainerElevation,
-        focusedElevation: Dp = FabPrimaryTokens.LoweredFocusContainerElevation,
-        hoveredElevation: Dp = FabPrimaryTokens.LoweredHoverContainerElevation,
+        defaultElevation: Dp = ElevationTokens.Level1,
+        pressedElevation: Dp = ElevationTokens.Level1,
+        focusedElevation: Dp = ElevationTokens.Level1,
+        hoveredElevation: Dp = ElevationTokens.Level2,
     ): FloatingActionButtonElevation =
         FloatingActionButtonElevation(
             defaultElevation = defaultElevation,
@@ -1404,22 +1425,27 @@
     fun asState(): State = animatable.asState()
 }
 
-private val SmallExtendedFabMinimumWidth = 56.dp
-private val SmallExtendedFabMinimumHeight = 56.dp
-private val SmallExtendedFabHorizontalPadding = 16.dp
-private val SmallExtendedFabIconPadding = 8.dp
+private val SmallExtendedFabMinimumWidth = ExtendedFabSmallTokens.ContainerHeight
+private val SmallExtendedFabMinimumHeight = ExtendedFabSmallTokens.ContainerHeight
+private val SmallExtendedFabPaddingStart = ExtendedFabSmallTokens.LeadingSpace
+private val SmallExtendedFabPaddingEnd = ExtendedFabSmallTokens.TrailingSpace
+private val SmallExtendedFabIconPadding = ExtendedFabSmallTokens.IconLabelSpace
 private val SmallExtendedFabTextStyle = TypographyKeyTokens.TitleMedium
 
-private val MediumExtendedFabMinimumWidth = 80.dp
-private val MediumExtendedFabMinimumHeight = 80.dp
-private val MediumExtendedFabHorizontalPadding = 26.dp
-private val MediumExtendedFabIconPadding = 16.dp
+private val MediumExtendedFabMinimumWidth = ExtendedFabMediumTokens.ContainerHeight
+private val MediumExtendedFabMinimumHeight = ExtendedFabMediumTokens.ContainerHeight
+private val MediumExtendedFabPaddingStart = ExtendedFabMediumTokens.LeadingSpace
+private val MediumExtendedFabPaddingEnd = ExtendedFabMediumTokens.TrailingSpace
+// TODO: ExtendedFabMediumTokens.IconLabelSpace is incorrect
+private val MediumExtendedFabIconPadding = 12.dp
 private val MediumExtendedFabTextStyle = TypographyKeyTokens.TitleLarge
 
-private val LargeExtendedFabMinimumWidth = 96.dp
-private val LargeExtendedFabMinimumHeight = 96.dp
-private val LargeExtendedFabHorizontalPadding = 28.dp
-private val LargeExtendedFabIconPadding = 20.dp
+private val LargeExtendedFabMinimumWidth = ExtendedFabLargeTokens.ContainerHeight
+private val LargeExtendedFabMinimumHeight = ExtendedFabLargeTokens.ContainerHeight
+private val LargeExtendedFabPaddingStart = ExtendedFabLargeTokens.LeadingSpace
+private val LargeExtendedFabPaddingEnd = ExtendedFabLargeTokens.TrailingSpace
+// TODO: ExtendedFabLargeTokens.IconLabelSpace is incorrect
+private val LargeExtendedFabIconPadding = 16.dp
 private val LargeExtendedFabTextStyle = TypographyKeyTokens.HeadlineSmall
 
 private val ExtendedFabStartIconPadding = 16.dp
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButtonMenu.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButtonMenu.kt
index 1abb428..1fb22a7 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButtonMenu.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/FloatingActionButtonMenu.kt
@@ -31,9 +31,13 @@
 import androidx.compose.foundation.layout.sizeIn
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.selection.toggleable
-import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.shape.GenericShape
 import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.tokens.FabBaselineTokens
+import androidx.compose.material3.tokens.FabLargeTokens
+import androidx.compose.material3.tokens.FabMediumTokens
+import androidx.compose.material3.tokens.FabMenuBaselineTokens
+import androidx.compose.material3.tokens.FabPrimaryContainerTokens
 import androidx.compose.material3.tokens.MotionSchemeKeyTokens
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -309,7 +313,7 @@
                         placeable.placeWithLayer(0, 0) { alpha = tempAlphaAnim.value }
                     }
                 },
-            shape = CircleShape,
+            shape = FabMenuBaselineTokens.ListItemContainerShape.value,
             color = containerColor,
             contentColor = contentColor,
             onClick = onClick
@@ -326,7 +330,10 @@
                         }
                     }
                     .sizeIn(minWidth = FabMenuItemMinWidth, minHeight = FabMenuItemHeight)
-                    .padding(horizontal = FabMenuItemContentPaddingHorizontal),
+                    .padding(
+                        start = FabMenuItemContentPaddingStart,
+                        end = FabMenuItemContentPaddingEnd
+                    ),
                 verticalAlignment = Alignment.CenterVertically,
                 horizontalArrangement =
                     Arrangement.spacedBy(
@@ -335,7 +342,10 @@
                     )
             ) {
                 icon()
-                text()
+                CompositionLocalProvider(
+                    LocalTextStyle provides MaterialTheme.typography.titleMedium,
+                    content = text
+                )
             }
         }
     }
@@ -586,26 +596,27 @@
     val checkedProgress: Float
 }
 
-private val FabInitialSize = 56.dp
+private val FabInitialSize = FabBaselineTokens.ContainerHeight
 private val FabInitialCornerRadius = 16.dp
-private val FabInitialIconSize = 24.dp
-private val FabMediumInitialSize = 80.dp
-private val FabMediumInitialCornerRadius = 24.dp
-private val FabMediumInitialIconSize = 28.dp
-private val FabLargeInitialSize = 96.dp
+private val FabInitialIconSize = FabBaselineTokens.IconSize
+private val FabMediumInitialSize = FabMediumTokens.ContainerHeight
+private val FabMediumInitialCornerRadius = 20.dp
+private val FabMediumInitialIconSize = FabMediumTokens.IconSize
+private val FabLargeInitialSize = FabLargeTokens.ContainerHeight
 private val FabLargeInitialCornerRadius = 28.dp
-private val FabLargeInitialIconSize = 36.dp
-private val FabFinalSize = 56.dp
+private val FabLargeInitialIconSize = 36.dp // TODO: FabLargeTokens.IconSize is incorrect
+private val FabFinalSize = FabMenuBaselineTokens.CloseButtonContainerHeight
 private val FabFinalCornerRadius = FabFinalSize.div(2)
-private val FabFinalIconSize = 20.dp
-private val FabShadowElevation = 6.dp
+private val FabFinalIconSize = FabMenuBaselineTokens.CloseButtonIconSize
+private val FabShadowElevation = FabPrimaryContainerTokens.ContainerElevation
 private val FabMenuPaddingHorizontal = 16.dp
-private val FabMenuPaddingBottom = 8.dp
+private val FabMenuPaddingBottom = FabMenuBaselineTokens.CloseButtonBetweenSpace
 private val FabMenuButtonPaddingBottom = 16.dp
-private val FabMenuItemMinWidth = 56.dp
-private val FabMenuItemHeight = 56.dp
-private val FabMenuItemSpacingVertical = 4.dp
-private val FabMenuItemContentPaddingHorizontal = 16.dp
-private val FabMenuItemContentSpacingHorizontal = 8.dp
+private val FabMenuItemMinWidth = FabMenuBaselineTokens.ListItemContainerHeight
+private val FabMenuItemHeight = FabMenuBaselineTokens.ListItemContainerHeight
+private val FabMenuItemSpacingVertical = FabMenuBaselineTokens.ListItemBetweenSpace
+private val FabMenuItemContentPaddingStart = FabMenuBaselineTokens.ListItemLeadingSpace
+private val FabMenuItemContentPaddingEnd = FabMenuBaselineTokens.ListItemTrailingSpace
+private val FabMenuItemContentSpacingHorizontal = FabMenuBaselineTokens.ListItemIconLabelSpace
 private const val StaggerEnterDelayMillis = 35
 private const val StaggerExitDelayMillis = 25
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
index 3fc2ed9..6337974 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IconButton.kt
@@ -30,7 +30,6 @@
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.internal.childSemantics
 import androidx.compose.material3.internal.rememberAnimatedShape
-import androidx.compose.material3.tokens.ColorSchemeKeyTokens
 import androidx.compose.material3.tokens.FilledIconButtonTokens
 import androidx.compose.material3.tokens.FilledTonalIconButtonTokens
 import androidx.compose.material3.tokens.LargeIconButtonTokens
@@ -85,14 +84,6 @@
  * IconButton with a color tint
  *
  * @sample androidx.compose.material3.samples.TintedIconButtonSample
- *
- * Small-sized narrow round shape IconButton
- *
- * @sample androidx.compose.material3.samples.XSmallNarrowSquareIconButtonsSample
- *
- * Medium / default size round-shaped icon button
- *
- * @sample androidx.compose.material3.samples.MediumRoundWideIconButtonSample
  * @param onClick called when this icon button is clicked
  * @param modifier the [Modifier] to be applied to this icon button
  * @param enabled controls the enabled state of this icon button. When `false`, this component will
@@ -106,7 +97,6 @@
  *   interactions will still happen internally.
  * @param content the content of this icon button, typically an [Icon]
  */
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Deprecated(
     message = "Use overload with `shape`",
     replaceWith =
@@ -120,7 +110,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
+    colors: IconButtonColors = IconButtonDefaults.iconButtonLocalContentColors(),
     interactionSource: MutableInteractionSource? = null,
     content: @Composable () -> Unit
 ) {
@@ -156,13 +146,22 @@
  * IconButton with a color tint
  *
  * @sample androidx.compose.material3.samples.TintedIconButtonSample
+ *
+ * Small-sized narrow round shape IconButton
+ *
+ * @sample androidx.compose.material3.samples.XSmallNarrowSquareIconButtonsSample
+ *
+ * Medium / default size round-shaped icon button
+ *
+ * @sample androidx.compose.material3.samples.MediumRoundWideIconButtonSample
  * @param onClick called when this icon button is clicked
  * @param modifier the [Modifier] to be applied to this icon button
  * @param enabled controls the enabled state of this icon button. When `false`, this component will
  *   not respond to user input, and it will appear visually disabled and disabled to accessibility
  *   services.
  * @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.iconButtonColors].
+ *   button in different states. See [IconButtonDefaults.iconButtonColors] and
+ *   [IconButtonDefaults.iconButtonLocalContentColors] .
  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
  *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
  *   appearance or preview the icon button in different states. Note that if `null` is provided,
@@ -176,7 +175,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
+    colors: IconButtonColors = IconButtonDefaults.iconButtonLocalContentColors(),
     interactionSource: MutableInteractionSource? = null,
     shape: Shape = IconButtonDefaults.standardShape,
     content: @Composable () -> Unit
@@ -250,7 +249,7 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonColors(),
+    colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonLocalContentColors(),
     interactionSource: MutableInteractionSource? = null,
     content: @Composable () -> Unit
 ) {
@@ -288,7 +287,8 @@
  *   not respond to user input, and it will appear visually disabled and disabled to accessibility
  *   services.
  * @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.iconToggleButtonColors].
+ *   button in different states. See [IconButtonDefaults.iconToggleButtonColors] and
+ *   [IconButtonDefaults.iconToggleButtonLocalContentColors].
  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
  *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
  *   appearance or preview the icon button in different states. Note that if `null` is provided,
@@ -303,7 +303,7 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonColors(),
+    colors: IconToggleButtonColors = IconButtonDefaults.iconToggleButtonLocalContentColors(),
     interactionSource: MutableInteractionSource? = null,
     shape: Shape = IconButtonDefaults.standardShape,
     content: @Composable () -> Unit
@@ -467,62 +467,6 @@
 
 /**
  * 
- * target="_blank">Material Design filled tonal icon button.
- *
- * Icon buttons help people take supplementary actions with a single tap. They’re used when a
- * compact button is required, such as in a toolbar or image list.
- *
- * ![Filled tonal icon button
- * image](https://developer.android.com/images/reference/androidx/compose/material3/filled-tonal-icon-button.png)
- *
- * A filled tonal icon button is a medium-emphasis icon button that is an alternative middle ground
- * between the default [FilledIconButton] and [OutlinedIconButton]. They can be used in contexts
- * where the lower-priority icon button requires slightly more emphasis than an outline would give.
- *
- * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
- * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
- * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
- *
- * Filled tonal icon button sample:
- *
- * @sample androidx.compose.material3.samples.FilledTonalIconButtonSample
- * @param onClick called when this icon button is clicked
- * @param modifier the [Modifier] to be applied to this icon button
- * @param enabled controls the enabled state of this icon button. When `false`, this component will
- *   not respond to user input, and it will appear visually disabled and disabled to accessibility
- *   services.
- * @param shape defines the shape of this icon button's container
- * @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.filledIconButtonColors].
- * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
- *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
- *   appearance or preview the icon button in different states. Note that if `null` is provided,
- *   interactions will still happen internally.
- * @param content the content of this icon button, typically an [Icon]
- */
-@Composable
-fun FilledTonalIconButton(
-    onClick: () -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    shape: Shape = IconButtonDefaults.filledShape,
-    colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
-    interactionSource: MutableInteractionSource? = null,
-    content: @Composable () -> Unit
-) =
-    SurfaceIconButton(
-        onClick = onClick,
-        modifier = modifier,
-        enabled = enabled,
-        shape = shape,
-        colors = colors,
-        border = null,
-        interactionSource = interactionSource,
-        content = content
-    )
-
-/**
- * 
  * target="_blank">Material Design filled icon toggle button.
  *
  * Icon buttons help people take supplementary actions with a single tap. They’re used when a
@@ -635,6 +579,62 @@
 
 /**
  * 
+ * target="_blank">Material Design filled tonal icon button.
+ *
+ * Icon buttons help people take supplementary actions with a single tap. They’re used when a
+ * compact button is required, such as in a toolbar or image list.
+ *
+ * ![Filled tonal icon button
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/filled-tonal-icon-button.png)
+ *
+ * A filled tonal icon button is a medium-emphasis icon button that is an alternative middle ground
+ * between the default [FilledIconButton] and [OutlinedIconButton]. They can be used in contexts
+ * where the lower-priority icon button requires slightly more emphasis than an outline would give.
+ *
+ * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
+ * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
+ * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
+ *
+ * Filled tonal icon button sample:
+ *
+ * @sample androidx.compose.material3.samples.FilledTonalIconButtonSample
+ * @param onClick called when this icon button is clicked
+ * @param modifier the [Modifier] to be applied to this icon button
+ * @param enabled controls the enabled state of this icon button. When `false`, this component will
+ *   not respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param shape defines the shape of this icon button's container
+ * @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
+ *   button in different states. See [IconButtonDefaults.filledIconButtonColors].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
+ *   appearance or preview the icon button in different states. Note that if `null` is provided,
+ *   interactions will still happen internally.
+ * @param content the content of this icon button, typically an [Icon]
+ */
+@Composable
+fun FilledTonalIconButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    shape: Shape = IconButtonDefaults.filledShape,
+    colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
+    interactionSource: MutableInteractionSource? = null,
+    content: @Composable () -> Unit
+) =
+    SurfaceIconButton(
+        onClick = onClick,
+        modifier = modifier,
+        enabled = enabled,
+        shape = shape,
+        colors = colors,
+        border = null,
+        interactionSource = interactionSource,
+        content = content
+    )
+
+/**
+ * 
  * target="_blank">Material Design filled tonal icon toggle button.
  *
  * Icon buttons help people take supplementary actions with a single tap. They’re used when a
@@ -788,9 +788,11 @@
  * @param shape defines the shape of this icon button's container and border (when [border] is not
  *   null)
  * @param colors [IconButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.outlinedIconButtonColors].
+ *   button in different states. See [IconButtonDefaults.outlinedIconButtonColors] and
+ *   [IconButtonDefaults.outlinedIconButtonLocalContentColors].
  * @param border the border to draw around the container of this icon button. Pass `null` for no
- *   border. See [IconButtonDefaults.outlinedIconButtonBorder].
+ *   border. See [IconButtonDefaults.outlinedIconButtonBorder] and
+ *   [IconButtonDefaults.outlinedIconButtonLocalContentColorBorder].
  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
  *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
  *   appearance or preview the icon button in different states. Note that if `null` is provided,
@@ -803,8 +805,8 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     shape: Shape = IconButtonDefaults.outlinedShape,
-    colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors(),
-    border: BorderStroke? = IconButtonDefaults.outlinedIconButtonBorder(enabled),
+    colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonLocalContentColors(),
+    border: BorderStroke? = IconButtonDefaults.outlinedIconButtonLocalContentColorBorder(enabled),
     interactionSource: MutableInteractionSource? = null,
     content: @Composable () -> Unit
 ) =
@@ -819,6 +821,125 @@
         content = content
     )
 
+/**
+ * 
+ * target="_blank">Material Design outlined icon toggle button.
+ *
+ * Icon buttons help people take supplementary actions with a single tap. They’re used when a
+ * compact button is required, such as in a toolbar or image list.
+ *
+ * ![Outlined icon toggle button
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/outlined-icon-toggle-button.png)
+ *
+ * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
+ * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
+ * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
+ *
+ * @sample androidx.compose.material3.samples.OutlinedIconToggleButtonSample
+ * @param checked whether this icon button is toggled on or off
+ * @param onCheckedChange called when this icon button is clicked
+ * @param modifier the [Modifier] to be applied to this icon button
+ * @param enabled controls the enabled state of this icon button. When `false`, this component will
+ *   not respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param shape defines the shape of this icon button's container and border (when [border] is not
+ *   null)
+ * @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
+ *   button in different states. See [IconButtonDefaults.outlinedIconToggleButtonColors] and
+ *   [IconButtonDefaults.outlinedIconToggleButtonLocalContentColors].
+ * @param border the border to draw around the container of this icon button. Pass `null` for no
+ *   border. See [IconButtonDefaults.outlinedIconToggleButtonBorder] and
+ *   [IconButtonDefaults.outlinedIconToggleButtonLocalContentColorBorder].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
+ *   appearance or preview the icon button in different states. Note that if `null` is provided,
+ *   interactions will still happen internally.
+ * @param content the content of this icon button, typically an [Icon]
+ */
+@Composable
+fun OutlinedIconToggleButton(
+    checked: Boolean,
+    onCheckedChange: (Boolean) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    shape: Shape = IconButtonDefaults.outlinedShape,
+    colors: IconToggleButtonColors =
+        IconButtonDefaults.outlinedIconToggleButtonLocalContentColors(),
+    border: BorderStroke? =
+        IconButtonDefaults.outlinedIconToggleButtonLocalContentColorBorder(enabled, checked),
+    interactionSource: MutableInteractionSource? = null,
+    content: @Composable () -> Unit
+) =
+    SurfaceIconToggleButton(
+        checked = checked,
+        onCheckedChange = onCheckedChange,
+        modifier = modifier.semantics { role = Role.Checkbox },
+        enabled = enabled,
+        shape = shape,
+        colors = colors,
+        border = border,
+        interactionSource = interactionSource,
+        content = content
+    )
+
+/**
+ * 
+ * target="_blank">Material Design outlined icon toggle button.
+ *
+ * Icon buttons help people take supplementary actions with a single tap. They’re used when a
+ * compact button is required, such as in a toolbar or image list.
+ *
+ * ![Outlined icon toggle button
+ * image](https://developer.android.com/images/reference/androidx/compose/material3/outlined-icon-toggle-button.png)
+ *
+ * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
+ * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
+ * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
+ *
+ * @sample androidx.compose.material3.samples.OutlinedIconToggleButtonWithAnimatedShapeSample
+ * @param checked whether this icon button is toggled on or off
+ * @param onCheckedChange called when this icon button is clicked
+ * @param shapes the [IconButtonShapes] that the icon toggle button will morph between depending on
+ *   the user's interaction with the icon toggle button.
+ * @param modifier the [Modifier] to be applied to this icon button
+ * @param enabled controls the enabled state of this icon button. When `false`, this component will
+ *   not respond to user input, and it will appear visually disabled and disabled to accessibility
+ *   services.
+ * @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
+ *   button in different states. See [IconButtonDefaults.outlinedIconToggleButtonColors].
+ * @param border the border to draw around the container of this icon button. Pass `null` for no
+ *   border. See [IconButtonDefaults.outlinedIconToggleButtonBorder].
+ * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
+ *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
+ *   appearance or preview the icon button in different states. Note that if `null` is provided,
+ *   interactions will still happen internally.
+ * @param content the content of this icon button, typically an [Icon]
+ */
+@ExperimentalMaterial3ExpressiveApi
+@Composable
+fun OutlinedIconToggleButton(
+    checked: Boolean,
+    onCheckedChange: (Boolean) -> Unit,
+    shapes: IconButtonShapes,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    colors: IconToggleButtonColors = IconButtonDefaults.outlinedIconToggleButtonColors(),
+    border: BorderStroke? = IconButtonDefaults.outlinedIconToggleButtonBorder(enabled, checked),
+    interactionSource: MutableInteractionSource? = null,
+    content: @Composable () -> Unit
+) =
+    SurfaceIconToggleButton(
+        checked = checked,
+        onCheckedChange = onCheckedChange,
+        modifier = modifier.semantics { role = Role.Checkbox },
+        enabled = enabled,
+        shapes = shapes,
+        colors = colors,
+        border = border,
+        interactionSource = interactionSource,
+        content = content
+    )
+
 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 private fun SurfaceIconButton(
@@ -950,132 +1071,20 @@
     return shapeByInteraction(shapes, pressed, checked, defaultAnimationSpec)
 }
 
-/**
- * 
- * target="_blank">Material Design outlined icon toggle button.
- *
- * Icon buttons help people take supplementary actions with a single tap. They’re used when a
- * compact button is required, such as in a toolbar or image list.
- *
- * ![Outlined icon toggle button
- * image](https://developer.android.com/images/reference/androidx/compose/material3/outlined-icon-toggle-button.png)
- *
- * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
- * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
- * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
- *
- * @sample androidx.compose.material3.samples.OutlinedIconToggleButtonSample
- * @param checked whether this icon button is toggled on or off
- * @param onCheckedChange called when this icon button is clicked
- * @param modifier the [Modifier] to be applied to this icon button
- * @param enabled controls the enabled state of this icon button. When `false`, this component will
- *   not respond to user input, and it will appear visually disabled and disabled to accessibility
- *   services.
- * @param shape defines the shape of this icon button's container and border (when [border] is not
- *   null)
- * @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.outlinedIconToggleButtonColors].
- * @param border the border to draw around the container of this icon button. Pass `null` for no
- *   border. See [IconButtonDefaults.outlinedIconToggleButtonBorder].
- * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
- *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
- *   appearance or preview the icon button in different states. Note that if `null` is provided,
- *   interactions will still happen internally.
- * @param content the content of this icon button, typically an [Icon]
- */
-@Composable
-fun OutlinedIconToggleButton(
-    checked: Boolean,
-    onCheckedChange: (Boolean) -> Unit,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    shape: Shape = IconButtonDefaults.outlinedShape,
-    colors: IconToggleButtonColors = IconButtonDefaults.outlinedIconToggleButtonColors(),
-    border: BorderStroke? = IconButtonDefaults.outlinedIconToggleButtonBorder(enabled, checked),
-    interactionSource: MutableInteractionSource? = null,
-    content: @Composable () -> Unit
-) =
-    SurfaceIconToggleButton(
-        checked = checked,
-        onCheckedChange = onCheckedChange,
-        modifier = modifier.semantics { role = Role.Checkbox },
-        enabled = enabled,
-        shape = shape,
-        colors = colors,
-        border = border,
-        interactionSource = interactionSource,
-        content = content
-    )
-
-/**
- * 
- * target="_blank">Material Design outlined icon toggle button.
- *
- * Icon buttons help people take supplementary actions with a single tap. They’re used when a
- * compact button is required, such as in a toolbar or image list.
- *
- * ![Outlined icon toggle button
- * image](https://developer.android.com/images/reference/androidx/compose/material3/outlined-icon-toggle-button.png)
- *
- * [content] should typically be an [Icon] (see [androidx.compose.material.icons.Icons]). If using a
- * custom icon, note that the typical size for the internal icon is 24 x 24 dp. This icon button has
- * an overall minimum touch target size of 48 x 48dp, to meet accessibility guidelines.
- *
- * @sample androidx.compose.material3.samples.OutlinedIconToggleButtonWithAnimatedShapeSample
- * @param checked whether this icon button is toggled on or off
- * @param onCheckedChange called when this icon button is clicked
- * @param shapes the [IconButtonShapes] that the icon toggle button will morph between depending on
- *   the user's interaction with the icon toggle button.
- * @param modifier the [Modifier] to be applied to this icon button
- * @param enabled controls the enabled state of this icon button. When `false`, this component will
- *   not respond to user input, and it will appear visually disabled and disabled to accessibility
- *   services.
- * @param colors [IconToggleButtonColors] that will be used to resolve the colors used for this icon
- *   button in different states. See [IconButtonDefaults.outlinedIconToggleButtonColors].
- * @param border the border to draw around the container of this icon button. Pass `null` for no
- *   border. See [IconButtonDefaults.outlinedIconToggleButtonBorder].
- * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
- *   emitting [Interaction]s for this icon button. You can use this to change the icon button's
- *   appearance or preview the icon button in different states. Note that if `null` is provided,
- *   interactions will still happen internally.
- * @param content the content of this icon button, typically an [Icon]
- */
-@ExperimentalMaterial3ExpressiveApi
-@Composable
-fun OutlinedIconToggleButton(
-    checked: Boolean,
-    onCheckedChange: (Boolean) -> Unit,
-    shapes: IconButtonShapes,
-    modifier: Modifier = Modifier,
-    enabled: Boolean = true,
-    colors: IconToggleButtonColors = IconButtonDefaults.outlinedIconToggleButtonColors(),
-    border: BorderStroke? = IconButtonDefaults.outlinedIconToggleButtonBorder(enabled, checked),
-    interactionSource: MutableInteractionSource? = null,
-    content: @Composable () -> Unit
-) =
-    SurfaceIconToggleButton(
-        checked = checked,
-        onCheckedChange = onCheckedChange,
-        modifier = modifier.semantics { role = Role.Checkbox },
-        enabled = enabled,
-        shapes = shapes,
-        colors = colors,
-        border = border,
-        interactionSource = interactionSource,
-        content = content
-    )
-
-/** Contains the default values used by all icon button types. */
+/** Contains the default values for all four icon and icon toggle button types. */
 object IconButtonDefaults {
-    /** Creates a [IconButtonColors] that represents the default colors used in a [IconButton]. */
+    /**
+     * Contains the default values used by [IconButton]. [LocalContentColor] will be applied to the
+     * icon and down the UI tree.
+     */
     @Composable
-    fun iconButtonColors(): IconButtonColors {
+    fun iconButtonLocalContentColors(): IconButtonColors {
         val contentColor = LocalContentColor.current
         val colors = MaterialTheme.colorScheme.defaultIconButtonColors(contentColor)
-        if (colors.contentColor == contentColor) {
-            return colors
+        return if (colors.contentColor == contentColor) {
+            colors
         } else {
-            return colors.copy(
+            colors.copy(
                 contentColor = contentColor,
                 disabledContentColor =
                     contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
@@ -1084,6 +1093,14 @@
     }
 
     /**
+     * Creates a [IconButtonColors] that represents the default colors used in a [IconButton]. See
+     * [iconButtonLocalContentColors] for default values that applies [LocalContentColor] to the
+     * icon and down the UI tree.
+     */
+    @Composable
+    fun iconButtonColors(): IconButtonColors = MaterialTheme.colorScheme.defaultIconButtonColors()
+
+    /**
      * Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
      *
      * @param containerColor the container color of this icon button when enabled.
@@ -1094,13 +1111,13 @@
     @Composable
     fun iconButtonColors(
         containerColor: Color = Color.Unspecified,
-        contentColor: Color = LocalContentColor.current,
+        contentColor: Color = Color.Unspecified,
         disabledContainerColor: Color = Color.Unspecified,
         disabledContentColor: Color =
             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
     ): IconButtonColors =
         MaterialTheme.colorScheme
-            .defaultIconButtonColors(LocalContentColor.current)
+            .defaultIconButtonColors()
             .copy(
                 containerColor = containerColor,
                 contentColor = contentColor,
@@ -1108,15 +1125,22 @@
                 disabledContentColor = disabledContentColor,
             )
 
-    internal fun ColorScheme.defaultIconButtonColors(localContentColor: Color): IconButtonColors {
+    internal fun ColorScheme.defaultIconButtonColors(
+        localContentColor: Color? = null,
+    ): IconButtonColors {
         return defaultIconButtonColorsCached
             ?: run {
                 IconButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = localContentColor,
+                        contentColor =
+                            localContentColor ?: fromToken(StandardIconButtonTokens.Color),
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
-                            localContentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
+                            localContentColor?.copy(
+                                alpha = StandardIconButtonTokens.DisabledOpacity
+                            )
+                                ?: fromToken(StandardIconButtonTokens.DisabledColor)
+                                    .copy(alpha = StandardIconButtonTokens.DisabledOpacity)
                     )
                     .also { defaultIconButtonColorsCached = it }
             }
@@ -1124,10 +1148,10 @@
 
     /**
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
-     * [IconToggleButton].
+     * [IconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI tree.
      */
     @Composable
-    fun iconToggleButtonColors(): IconToggleButtonColors {
+    fun iconToggleButtonLocalContentColors(): IconToggleButtonColors {
         val contentColor = LocalContentColor.current
         val colors = MaterialTheme.colorScheme.defaultIconToggleButtonColors(contentColor)
         if (colors.contentColor == contentColor) {
@@ -1143,6 +1167,15 @@
 
     /**
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
+     * [IconToggleButton]. See [iconToggleButtonLocalContentColors] for default values that applies
+     * [LocalContentColor] to the icon and down the UI tree.
+     */
+    @Composable
+    fun iconToggleButtonColors(): IconToggleButtonColors =
+        MaterialTheme.colorScheme.defaultIconToggleButtonColors()
+
+    /**
+     * Creates a [IconToggleButtonColors] that represents the default colors used in a
      * [IconToggleButton].
      *
      * @param containerColor the container color of this icon button when enabled.
@@ -1155,7 +1188,7 @@
     @Composable
     fun iconToggleButtonColors(
         containerColor: Color = Color.Unspecified,
-        contentColor: Color = LocalContentColor.current,
+        contentColor: Color = Color.Unspecified,
         disabledContainerColor: Color = Color.Unspecified,
         disabledContentColor: Color =
             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity),
@@ -1163,7 +1196,7 @@
         checkedContentColor: Color = Color.Unspecified
     ): IconToggleButtonColors =
         MaterialTheme.colorScheme
-            .defaultIconToggleButtonColors(LocalContentColor.current)
+            .defaultIconToggleButtonColors()
             .copy(
                 containerColor = containerColor,
                 contentColor = contentColor,
@@ -1174,18 +1207,22 @@
             )
 
     internal fun ColorScheme.defaultIconToggleButtonColors(
-        localContentColor: Color
+        localContentColor: Color? = null,
     ): IconToggleButtonColors {
         return defaultIconToggleButtonColorsCached
             ?: run {
                 IconToggleButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = localContentColor,
+                        contentColor =
+                            localContentColor
+                                ?: fromToken(StandardIconButtonTokens.UnselectedColor),
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
-                            localContentColor.copy(
+                            localContentColor?.copy(
                                 alpha = StandardIconButtonTokens.DisabledOpacity
-                            ),
+                            )
+                                ?: fromToken(StandardIconButtonTokens.DisabledColor)
+                                    .copy(alpha = StandardIconButtonTokens.DisabledOpacity),
                         checkedContainerColor = Color.Transparent,
                         checkedContentColor = fromToken(StandardIconButtonTokens.SelectedColor)
                     )
@@ -1227,8 +1264,7 @@
             return defaultFilledIconButtonColorsCached
                 ?: IconButtonColors(
                         containerColor = fromToken(FilledIconButtonTokens.ContainerColor),
-                        contentColor =
-                            contentColorFor(fromToken(FilledIconButtonTokens.ContainerColor)),
+                        contentColor = fromToken(FilledIconButtonTokens.Color),
                         disabledContainerColor =
                             fromToken(FilledIconButtonTokens.DisabledContainerColor)
                                 .copy(alpha = FilledIconButtonTokens.DisabledContainerOpacity),
@@ -1295,10 +1331,7 @@
                                 .copy(alpha = FilledIconButtonTokens.DisabledOpacity),
                         checkedContainerColor =
                             fromToken(FilledIconButtonTokens.SelectedContainerColor),
-                        checkedContentColor =
-                            contentColorFor(
-                                fromToken(FilledIconButtonTokens.SelectedContainerColor)
-                            )
+                        checkedContentColor = fromToken(FilledIconButtonTokens.SelectedColor)
                     )
                     .also { defaultFilledIconToggleButtonColorsCached = it }
         }
@@ -1339,8 +1372,7 @@
             return defaultFilledTonalIconButtonColorsCached
                 ?: IconButtonColors(
                         containerColor = fromToken(FilledTonalIconButtonTokens.ContainerColor),
-                        contentColor =
-                            contentColorFor(fromToken(FilledTonalIconButtonTokens.ContainerColor)),
+                        contentColor = fromToken(FilledTonalIconButtonTokens.Color),
                         disabledContainerColor =
                             fromToken(FilledTonalIconButtonTokens.DisabledContainerColor)
                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
@@ -1394,10 +1426,7 @@
                 ?: IconToggleButtonColors(
                         containerColor =
                             fromToken(FilledTonalIconButtonTokens.UnselectedContainerColor),
-                        contentColor =
-                            contentColorFor(
-                                fromToken(FilledTonalIconButtonTokens.UnselectedContainerColor)
-                            ),
+                        contentColor = fromToken(FilledTonalIconButtonTokens.UnselectedColor),
                         disabledContainerColor =
                             fromToken(FilledTonalIconButtonTokens.DisabledContainerColor)
                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
@@ -1406,23 +1435,19 @@
                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledOpacity),
                         checkedContainerColor =
                             fromToken(FilledTonalIconButtonTokens.SelectedContainerColor),
-                        checkedContentColor =
-                            contentColorFor(
-                                fromToken(FilledTonalIconButtonTokens.SelectedContainerColor)
-                            )
+                        checkedContentColor = fromToken(FilledTonalIconButtonTokens.SelectedColor)
                     )
                     .also { defaultFilledTonalIconToggleButtonColorsCached = it }
         }
 
     /**
      * Creates a [IconButtonColors] that represents the default colors used in a
-     * [OutlinedIconButton].
+     * [OutlinedIconButton]. [LocalContentColor] will be applied to the icon and down the UI tree.
      */
     @Composable
-    fun outlinedIconButtonColors(): IconButtonColors {
-        val colors =
-            MaterialTheme.colorScheme.defaultOutlinedIconButtonColors(LocalContentColor.current)
+    fun outlinedIconButtonLocalContentColors(): IconButtonColors {
         val contentColor = LocalContentColor.current
+        val colors = MaterialTheme.colorScheme.defaultOutlinedIconButtonColors(contentColor)
         if (colors.contentColor == contentColor) {
             return colors
         } else {
@@ -1438,6 +1463,17 @@
      * Creates a [IconButtonColors] that represents the default colors used in a
      * [OutlinedIconButton].
      *
+     * See [outlinedIconButtonLocalContentColors] for default values that applies
+     * [LocalContentColor] to the icon and down the UI tree.
+     */
+    @Composable
+    fun outlinedIconButtonColors(): IconButtonColors =
+        MaterialTheme.colorScheme.defaultOutlinedIconButtonColors()
+
+    /**
+     * Creates a [IconButtonColors] that represents the default colors used in a
+     * [OutlinedIconButton].
+     *
      * @param containerColor the container color of this icon button when enabled.
      * @param contentColor the content color of this icon button when enabled.
      * @param disabledContainerColor the container color of this icon button when not enabled.
@@ -1446,13 +1482,13 @@
     @Composable
     fun outlinedIconButtonColors(
         containerColor: Color = Color.Unspecified,
-        contentColor: Color = LocalContentColor.current,
+        contentColor: Color = Color.Unspecified,
         disabledContainerColor: Color = Color.Unspecified,
         disabledContentColor: Color =
             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
     ): IconButtonColors =
         MaterialTheme.colorScheme
-            .defaultOutlinedIconButtonColors(LocalContentColor.current)
+            .defaultOutlinedIconButtonColors()
             .copy(
                 containerColor = containerColor,
                 contentColor = contentColor,
@@ -1461,16 +1497,21 @@
             )
 
     internal fun ColorScheme.defaultOutlinedIconButtonColors(
-        localContentColor: Color
+        localContentColor: Color? = null
     ): IconButtonColors {
         return defaultOutlinedIconButtonColorsCached
             ?: run {
                 IconButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = localContentColor,
+                        contentColor =
+                            localContentColor ?: fromToken(OutlinedIconButtonTokens.Color),
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
-                            localContentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
+                            localContentColor?.copy(
+                                alpha = OutlinedIconButtonTokens.DisabledOpacity
+                            )
+                                ?: fromToken(OutlinedIconButtonTokens.DisabledColor)
+                                    .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
                     )
                     .also { defaultOutlinedIconButtonColorsCached = it }
             }
@@ -1478,10 +1519,11 @@
 
     /**
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
-     * [OutlinedIconToggleButton].
+     * [OutlinedIconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI
+     * tree.
      */
     @Composable
-    fun outlinedIconToggleButtonColors(): IconToggleButtonColors {
+    fun outlinedIconToggleButtonLocalContentColors(): IconToggleButtonColors {
         val contentColor = LocalContentColor.current
         val colors = MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonColors(contentColor)
         if (colors.contentColor == contentColor) {
@@ -1499,6 +1541,17 @@
      * Creates a [IconToggleButtonColors] that represents the default colors used in a
      * [OutlinedIconToggleButton].
      *
+     * See [outlinedIconToggleButtonLocalContentColors] for default values that applies
+     * [LocalContentColor] to the icon and down the UI tree.
+     */
+    @Composable
+    fun outlinedIconToggleButtonColors(): IconToggleButtonColors =
+        MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonColors()
+
+    /**
+     * Creates a [IconToggleButtonColors] that represents the default colors used in a
+     * [OutlinedIconToggleButton].
+     *
      * @param containerColor the container color of this icon button when enabled.
      * @param contentColor the content color of this icon button when enabled.
      * @param disabledContainerColor the container color of this icon button when not enabled.
@@ -1509,7 +1562,7 @@
     @Composable
     fun outlinedIconToggleButtonColors(
         containerColor: Color = Color.Unspecified,
-        contentColor: Color = LocalContentColor.current,
+        contentColor: Color = Color.Unspecified,
         disabledContainerColor: Color = Color.Unspecified,
         disabledContentColor: Color =
             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
@@ -1517,7 +1570,7 @@
         checkedContentColor: Color = contentColorFor(checkedContainerColor)
     ): IconToggleButtonColors =
         MaterialTheme.colorScheme
-            .defaultOutlinedIconToggleButtonColors(LocalContentColor.current)
+            .defaultOutlinedIconToggleButtonColors()
             .copy(
                 containerColor = containerColor,
                 contentColor = contentColor,
@@ -1528,23 +1581,25 @@
             )
 
     internal fun ColorScheme.defaultOutlinedIconToggleButtonColors(
-        localContentColor: Color
+        localContentColor: Color? = null
     ): IconToggleButtonColors {
         return defaultOutlinedIconToggleButtonColorsCached
             ?: run {
                 IconToggleButtonColors(
                         containerColor = Color.Transparent,
-                        contentColor = localContentColor,
+                        contentColor =
+                            localContentColor
+                                ?: fromToken(OutlinedIconButtonTokens.UnselectedColor),
                         disabledContainerColor = Color.Transparent,
                         disabledContentColor =
-                            localContentColor.copy(
+                            localContentColor?.copy(
                                 alpha = OutlinedIconButtonTokens.DisabledOpacity
-                            ),
-                        checkedContainerColor = fromToken(ColorSchemeKeyTokens.InverseSurface),
-                        checkedContentColor =
-                            contentColorFor(
-                                fromToken(OutlinedIconButtonTokens.SelectedContainerColor)
                             )
+                                ?: fromToken(OutlinedIconButtonTokens.DisabledColor)
+                                    .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
+                        checkedContainerColor =
+                            fromToken(OutlinedIconButtonTokens.SelectedContainerColor),
+                        checkedContentColor = fromToken(OutlinedIconButtonTokens.SelectedColor)
                     )
                     .also { defaultOutlinedIconToggleButtonColorsCached = it }
             }
@@ -1558,6 +1613,24 @@
      * @param checked whether the icon button is checked
      */
     @Composable
+    fun outlinedIconToggleButtonLocalContentColorBorder(
+        enabled: Boolean,
+        checked: Boolean
+    ): BorderStroke? {
+        if (checked) {
+            return null
+        }
+        return outlinedIconButtonLocalContentColorBorder(enabled)
+    }
+
+    /**
+     * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] and
+     * [checked] state.
+     *
+     * @param enabled whether the icon button is enabled
+     * @param checked whether the icon button is checked
+     */
+    @Composable
     fun outlinedIconToggleButtonBorder(enabled: Boolean, checked: Boolean): BorderStroke? {
         if (checked) {
             return null
@@ -1565,6 +1638,18 @@
         return outlinedIconButtonBorder(enabled)
     }
 
+    @Composable
+    fun outlinedIconButtonLocalContentColorBorder(enabled: Boolean): BorderStroke? {
+        val outlineColor = LocalContentColor.current
+        val color: Color =
+            if (enabled) {
+                outlineColor
+            } else {
+                outlineColor.copy(alpha = OutlinedIconButtonTokens.DisabledContainerOpacity)
+            }
+        return remember(color) { BorderStroke(SmallIconButtonTokens.OutlinedOutlineWidth, color) }
+    }
+
     /**
      * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] state.
      *
@@ -1572,13 +1657,12 @@
      */
     @Composable
     fun outlinedIconButtonBorder(enabled: Boolean): BorderStroke {
+        val outlineColor = OutlinedIconButtonTokens.OutlineColor.value
         val color: Color =
             if (enabled) {
-                LocalContentColor.current
+                outlineColor
             } else {
-                LocalContentColor.current.copy(
-                    alpha = OutlinedIconButtonTokens.DisabledContainerOpacity
-                )
+                outlineColor.copy(alpha = OutlinedIconButtonTokens.DisabledContainerOpacity)
             }
         return remember(color) { BorderStroke(SmallIconButtonTokens.OutlinedOutlineWidth, color) }
     }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
index 024072c..2dca2f5 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SplitButton.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose.material3
 
-import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.AnimationVector1D
 import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.interaction.Interaction
@@ -34,24 +32,18 @@
 import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.internal.ProvideContentColorTextStyle
+import androidx.compose.material3.internal.rememberAnimatedShape
 import androidx.compose.material3.tokens.MotionSchemeKeyTokens
 import androidx.compose.material3.tokens.ShapeTokens
 import androidx.compose.material3.tokens.SplitButtonSmallTokens
 import androidx.compose.material3.tokens.StateTokens
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithContent
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Outline
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.graphics.drawOutline
 import androidx.compose.ui.layout.Layout
@@ -60,9 +52,7 @@
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.constrainHeight
 import androidx.compose.ui.unit.constrainWidth
 import androidx.compose.ui.unit.dp
@@ -70,9 +60,6 @@
 import androidx.compose.ui.util.fastFirst
 import androidx.compose.ui.util.fastMaxOfOrNull
 import androidx.compose.ui.util.fastSumBy
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
 
 /**
  * A [SplitButton] let user define a button group consisting of 2 buttons. The leading button
@@ -579,9 +566,10 @@
      * @param onClick called when the button is clicked
      * @param modifier the [Modifier] to be applied to this button.
      * @param enabled controls the enabled state of the split button. When `false`, this component
-     *   will
-     * @param shapes defines the shapes of this button's container, border (when [border] is not
-     *   null), and shadow (when using [elevation])
+     *   will not respond to user input, and it will appear visually disabled and disabled to
+     *   accessibility services.
+     * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+     *   on the user's interaction with the button.
      * @param colors [ButtonColors] that will be used to resolve the colors for this button in
      *   different states. See [ButtonDefaults.buttonColors].
      * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
@@ -659,9 +647,10 @@
      *   trigger the corner morphing animation to reflect the updated state.
      * @param modifier the [Modifier] to be applied to this button.
      * @param enabled controls the enabled state of the split button. When `false`, this component
-     *   will
-     * @param shapes the shapes for the container when transition between different
-     *   [ShapeAnimationState]
+     *   will not respond to user input, and it will appear visually disabled and disabled to
+     *   accessibility services.
+     * @param shapes the [SplitButtonShapes] that the trailing button will morph between depending
+     *   on the user's interaction with the button.
      * @param colors [ButtonColors] that will be used to resolve the colors for this button in
      *   different states. See [ButtonDefaults.buttonColors].
      * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
@@ -901,92 +890,17 @@
     checked: Boolean,
     animationSpec: FiniteAnimationSpec
 ): Shape {
+    val shape =
+        if (pressed) {
+            shapes.pressedShape ?: shapes.shape
+        } else if (checked) {
+            shapes.checkedShape ?: shapes.shape
+        } else shapes.shape
+
     if (shapes.hasRoundedCornerShapes) {
-        return rememberAnimatedShape(shapes, pressed, checked, animationSpec)
+        return rememberAnimatedShape(shape as RoundedCornerShape, animationSpec)
     }
-    if (pressed) {
-        return shapes.pressedShape ?: shapes.shape
-    }
-    if (checked) {
-        return shapes.checkedShape ?: shapes.shape
-    }
-    return shapes.shape
-}
-
-@Composable
-private fun rememberAnimatedShape(
-    shapes: SplitButtonShapes,
-    pressed: Boolean,
-    checked: Boolean,
-    animationSpec: FiniteAnimationSpec,
-): Shape {
-    val defaultShape = shapes.shape as RoundedCornerShape
-    val pressedShape = shapes.pressedShape as RoundedCornerShape?
-    val checkedShape = shapes.checkedShape as RoundedCornerShape?
-    val currentShape =
-        if (pressedShape != null && pressed) pressedShape
-        else if (checkedShape != null && checked) checkedShape else defaultShape
-
-    val state =
-        remember(animationSpec) {
-            ShapeAnimationState(
-                shape = currentShape,
-                spec = animationSpec,
-            )
-        }
-
-    val channel = remember { Channel(Channel.CONFLATED) }
-    SideEffect { channel.trySend(currentShape) }
-    LaunchedEffect(state, channel) {
-        for (target in channel) {
-            val newTarget = channel.tryReceive().getOrNull() ?: target
-            launch { state.animateToShape(newTarget) }
-        }
-    }
-
-    return rememberAnimatedShape(state)
-}
-
-@Composable
-private fun rememberAnimatedShape(state: ShapeAnimationState): Shape {
-    val density = LocalDensity.current
-    state.density = density
-
-    return remember(density, state) {
-        object : ShapeWithOpticalCentering {
-            var clampedRange by mutableStateOf(0f..1f)
-
-            override fun offset(): Float {
-                val topStart = state.topStart?.value?.coerceIn(clampedRange) ?: 0f
-                val topEnd = state.topEnd?.value?.coerceIn(clampedRange) ?: 0f
-                val bottomStart = state.bottomStart?.value?.coerceIn(clampedRange) ?: 0f
-                val bottomEnd = state.bottomEnd?.value?.coerceIn(clampedRange) ?: 0f
-                val avgStart = (topStart + bottomStart) / 2
-                val avgEnd = (topEnd + bottomEnd) / 2
-                return OpticalCenteringCoefficient * (avgStart - avgEnd)
-            }
-
-            override fun createOutline(
-                size: Size,
-                layoutDirection: LayoutDirection,
-                density: Density
-            ): Outline {
-                state.size = size
-                if (!state.didInit) {
-                    state.init()
-                }
-
-                clampedRange = 0f..size.height / 2
-                return RoundedCornerShape(
-                        topStart = state.topStart?.value?.coerceIn(clampedRange) ?: 0f,
-                        topEnd = state.topEnd?.value?.coerceIn(clampedRange) ?: 0f,
-                        bottomStart = state.bottomStart?.value?.coerceIn(clampedRange) ?: 0f,
-                        bottomEnd = state.bottomEnd?.value?.coerceIn(clampedRange) ?: 0f,
-                    )
-                    .createOutline(size, layoutDirection, density)
-            }
-        }
-    }
+    return shape
 }
 
 /**
@@ -1007,45 +921,5 @@
         return shape is RoundedCornerShape
     }
 
-@Stable
-private class ShapeAnimationState(
-    val shape: RoundedCornerShape,
-    val spec: FiniteAnimationSpec,
-) {
-    var size: Size = Size.Zero
-    var density: Density = Density(0f, 0f)
-    var didInit = false
-
-    var topStart: Animatable? = null
-        private set
-
-    var topEnd: Animatable? = null
-        private set
-
-    var bottomStart: Animatable? = null
-        private set
-
-    var bottomEnd: Animatable? = null
-        private set
-
-    fun init() {
-        topStart = Animatable(shape.topStart.toPx(size, density))
-        topEnd = Animatable(shape.topEnd.toPx(size, density))
-        bottomStart = Animatable(shape.bottomStart.toPx(size, density))
-        bottomEnd = Animatable(shape.bottomEnd.toPx(size, density))
-        didInit = true
-    }
-
-    suspend fun animateToShape(shape: RoundedCornerShape?) =
-        shape?.let {
-            coroutineScope {
-                launch { topStart?.animateTo(it.topStart.toPx(size, density), spec) }
-                launch { topEnd?.animateTo(it.topEnd.toPx(size, density), spec) }
-                launch { bottomStart?.animateTo(it.bottomStart.toPx(size, density), spec) }
-                launch { bottomEnd?.animateTo(it.bottomEnd.toPx(size, density), spec) }
-            }
-        }
-}
-
 private const val LeadingButtonLayoutId = "LeadingButton"
 private const val TrailingButtonLayoutId = "TrailingButton"
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabLargeTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabLargeTokens.kt
new file mode 100644
index 0000000..7b339a7
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabLargeTokens.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object ExtendedFabLargeTokens {
+    val ContainerHeight = 96.0.dp
+    val ContainerShape = ShapeKeyTokens.CornerExtraLarge
+    val IconLabelSpace = 20.0.dp
+    val IconSize = 32.0.dp
+    val LeadingSpace = 28.0.dp
+    val TrailingSpace = 28.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabMediumTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabMediumTokens.kt
new file mode 100644
index 0000000..3f6c72ff
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabMediumTokens.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object ExtendedFabMediumTokens {
+    val ContainerHeight = 80.0.dp
+    // TODO: uncomment when ShapeKeyTokens.CornerLargeIncreased is available
+    // val ContainerShape = ShapeKeyTokens.CornerLargeIncreased
+    val IconLabelSpace = 16.0.dp
+    val IconSize = 28.0.dp
+    val LeadingSpace = 26.0.dp
+    val TrailingSpace = 26.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabSmallTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabSmallTokens.kt
new file mode 100644
index 0000000..6a51bb1
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ExtendedFabSmallTokens.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object ExtendedFabSmallTokens {
+    val ContainerHeight = 56.0.dp
+    val ContainerShape = ShapeKeyTokens.CornerLarge
+    val IconLabelSpace = 8.0.dp
+    val IconSize = 24.0.dp
+    val LeadingSpace = 16.0.dp
+    val TrailingSpace = 16.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabBaselineTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabBaselineTokens.kt
new file mode 100644
index 0000000..f4f3506
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabBaselineTokens.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object FabBaselineTokens {
+    val ContainerHeight = 56.0.dp
+    val ContainerShape = ShapeKeyTokens.CornerLarge
+    val ContainerWidth = 56.0.dp
+    val IconSize = 24.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabLargeTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabLargeTokens.kt
new file mode 100644
index 0000000..57421b1
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabLargeTokens.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object FabLargeTokens {
+    val ContainerHeight = 96.0.dp
+    val ContainerShape = ShapeKeyTokens.CornerExtraLarge
+    val ContainerWidth = 96.0.dp
+    val IconSize = 32.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMediumTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMediumTokens.kt
new file mode 100644
index 0000000..70853b3
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMediumTokens.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object FabMediumTokens {
+    val ContainerHeight = 80.0.dp
+    // TODO: uncomment when ShapeKeyTokens.CornerLargeIncreased is available
+    // val ContainerShape = ShapeKeyTokens.CornerLargeIncreased
+    val ContainerWidth = 80.0.dp
+    val IconSize = 28.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMenuBaselineTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMenuBaselineTokens.kt
new file mode 100644
index 0000000..4c8771a
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabMenuBaselineTokens.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+import androidx.compose.ui.unit.dp
+
+internal object FabMenuBaselineTokens {
+    val CloseButtonBetweenSpace = 8.0.dp
+    val CloseButtonContainerElevation = ElevationTokens.Level3
+    val CloseButtonContainerHeight = 56.0.dp
+    val CloseButtonContainerShape = ShapeKeyTokens.CornerFull
+    val CloseButtonContainerWidth = 56.0.dp
+    val CloseButtonIconSize = 20.0.dp
+    val ListItemBetweenSpace = 4.0.dp
+    val ListItemContainerElevation = ElevationTokens.Level3
+    val ListItemContainerHeight = 56.0.dp
+    val ListItemContainerShape = ShapeKeyTokens.CornerFull
+    val ListItemIconLabelSpace = 8.0.dp
+    val ListItemIconSize = 24.0.dp
+    val ListItemLeadingSpace = 24.0.dp
+    val ListItemTrailingSpace = 24.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryContainerTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryContainerTokens.kt
new file mode 100644
index 0000000..4f273ca
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryContainerTokens.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+internal object FabPrimaryContainerTokens {
+    val ContainerColor = ColorSchemeKeyTokens.PrimaryContainer
+    val ContainerElevation = ElevationTokens.Level3
+    val FocusedContainerElevation = ElevationTokens.Level3
+    val FocusedIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
+    val HoveredContainerElevation = ElevationTokens.Level4
+    val HoveredIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
+    val IconColor = ColorSchemeKeyTokens.OnPrimaryContainer
+    val PressedContainerElevation = ElevationTokens.Level3
+    val PressedIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryLargeTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryLargeTokens.kt
deleted file mode 100644
index 2330a5c..0000000
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryLargeTokens.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// VERSION: v0_103
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-package androidx.compose.material3.tokens
-
-import androidx.compose.ui.unit.dp
-
-internal object FabPrimaryLargeTokens {
-    val ContainerColor = ColorSchemeKeyTokens.PrimaryContainer
-    val ContainerElevation = ElevationTokens.Level3
-    val ContainerHeight = 96.0.dp
-    val ContainerShape = ShapeKeyTokens.CornerExtraLarge
-    val ContainerWidth = 96.0.dp
-    val FocusContainerElevation = ElevationTokens.Level3
-    val FocusIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val HoverContainerElevation = ElevationTokens.Level4
-    val HoverIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconSize = 36.0.dp
-    val LoweredContainerElevation = ElevationTokens.Level1
-    val LoweredFocusContainerElevation = ElevationTokens.Level1
-    val LoweredHoverContainerElevation = ElevationTokens.Level2
-    val LoweredPressedContainerElevation = ElevationTokens.Level1
-    val PressedContainerElevation = ElevationTokens.Level3
-    val PressedIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimarySmallTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimarySmallTokens.kt
deleted file mode 100644
index 106084a..0000000
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimarySmallTokens.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// VERSION: v0_103
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-package androidx.compose.material3.tokens
-
-import androidx.compose.ui.unit.dp
-
-internal object FabPrimarySmallTokens {
-    val ContainerColor = ColorSchemeKeyTokens.PrimaryContainer
-    val ContainerElevation = ElevationTokens.Level3
-    val ContainerHeight = 40.0.dp
-    val ContainerShape = ShapeKeyTokens.CornerMedium
-    val ContainerWidth = 40.0.dp
-    val FocusContainerElevation = ElevationTokens.Level3
-    val FocusIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val HoverContainerElevation = ElevationTokens.Level4
-    val HoverIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconSize = 24.0.dp
-    val LoweredContainerElevation = ElevationTokens.Level1
-    val LoweredFocusContainerElevation = ElevationTokens.Level1
-    val LoweredHoverContainerElevation = ElevationTokens.Level2
-    val LoweredPressedContainerElevation = ElevationTokens.Level1
-    val PressedContainerElevation = ElevationTokens.Level3
-    val PressedIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryTokens.kt
deleted file mode 100644
index 6ee7c71..0000000
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabPrimaryTokens.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// VERSION: v0_103
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-package androidx.compose.material3.tokens
-
-import androidx.compose.ui.unit.dp
-
-internal object FabPrimaryTokens {
-    val ContainerColor = ColorSchemeKeyTokens.PrimaryContainer
-    val ContainerElevation = ElevationTokens.Level3
-    val ContainerHeight = 56.0.dp
-    val ContainerShape = ShapeKeyTokens.CornerLarge
-    val ContainerWidth = 56.0.dp
-    val FocusContainerElevation = ElevationTokens.Level3
-    val FocusIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val HoverContainerElevation = ElevationTokens.Level4
-    val HoverIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-    val IconSize = 24.0.dp
-    val LoweredContainerElevation = ElevationTokens.Level1
-    val LoweredFocusContainerElevation = ElevationTokens.Level1
-    val LoweredHoverContainerElevation = ElevationTokens.Level2
-    val LoweredPressedContainerElevation = ElevationTokens.Level1
-    val PressedContainerElevation = ElevationTokens.Level3
-    val PressedIconColor = ColorSchemeKeyTokens.OnPrimaryContainer
-}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryContainerTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryContainerTokens.kt
new file mode 100644
index 0000000..a419646
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryContainerTokens.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+internal object FabSecondaryContainerTokens {
+    val ContainerColor = ColorSchemeKeyTokens.SecondaryContainer
+    val ContainerElevation = ElevationTokens.Level3
+    val FocusedContainerElevation = ElevationTokens.Level3
+    val FocusedIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val HoveredContainerElevation = ElevationTokens.Level4
+    val HoveredIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val IconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val PressedContainerElevation = ElevationTokens.Level3
+    val PressedIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryTokens.kt
deleted file mode 100644
index ce17e1b..0000000
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSecondaryTokens.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// VERSION: v0_103
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-package androidx.compose.material3.tokens
-
-import androidx.compose.ui.unit.dp
-
-internal object FabSecondaryTokens {
-    val ContainerColor = ColorSchemeKeyTokens.SecondaryContainer
-    val ContainerElevation = ElevationTokens.Level3
-    val ContainerHeight = 56.0.dp
-    val ContainerShape = ShapeKeyTokens.CornerLarge
-    val ContainerWidth = 56.0.dp
-    val FocusContainerElevation = ElevationTokens.Level3
-    val FocusIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
-    val HoverContainerElevation = ElevationTokens.Level4
-    val HoverIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
-    val IconColor = ColorSchemeKeyTokens.OnSecondaryContainer
-    val IconSize = 24.0.dp
-    val LoweredContainerElevation = ElevationTokens.Level1
-    val LoweredFocusContainerElevation = ElevationTokens.Level1
-    val LoweredHoverContainerElevation = ElevationTokens.Level2
-    val LoweredPressedContainerElevation = ElevationTokens.Level1
-    val PressedContainerElevation = ElevationTokens.Level3
-    val PressedIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
-}
diff --git a/tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSmallTokens.kt
similarity index 60%
copy from tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt
copy to compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSmallTokens.kt
index 3fa6028..da6ea8e 100644
--- a/tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/FabSmallTokens.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 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.
@@ -13,10 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_14_0
+// GENERATED CODE - DO NOT MODIFY BY HAND
 
-package androidx.tv.integration.presentation
+package androidx.compose.material3.tokens
 
-import android.content.res.AssetManager
+import androidx.compose.ui.unit.dp
 
-fun AssetManager.readAssetsFile(fileName: String): String =
-    open(fileName).bufferedReader().use { it.readText() }
+internal object FabSmallTokens {
+    val ContainerHeight = 40.0.dp
+    val ContainerShape = ShapeKeyTokens.CornerMedium
+    val ContainerWidth = 40.0.dp
+    val IconSize = 24.0.dp
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarHorizontalItemTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarHorizontalItemTokens.kt
index bdecc5f..fba7659 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarHorizontalItemTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarHorizontalItemTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarTokens.kt
index 4842560..352fe47 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarVerticalItemTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarVerticalItemTokens.kt
index 5452b98..c901af7 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarVerticalItemTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationBarVerticalItemTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailBaselineItemTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailBaselineItemTokens.kt
index 144c675..7e5c0b3 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailBaselineItemTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailBaselineItemTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailCollapsedTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailCollapsedTokens.kt
index 4827019..c4ad2b0 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailCollapsedTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailCollapsedTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailColorTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailColorTokens.kt
index 951345a..68a5be1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailColorTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailColorTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailExpandedTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailExpandedTokens.kt
index 9270c7e..34be029 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailExpandedTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailExpandedTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailHorizontalItemTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailHorizontalItemTokens.kt
index 1c8d76a..9261d3a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailHorizontalItemTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailHorizontalItemTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailVerticalItemTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailVerticalItemTokens.kt
index a87af2b..c398fc6 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailVerticalItemTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/NavigationRailVerticalItemTokens.kt
@@ -13,13 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// VERSION: v0_11_0
 // GENERATED CODE - DO NOT MODIFY BY HAND
-// TO MODIFY THIS FILE UPDATE:
-//   ux/material/dsdb/contrib/generators/tokens/src/compose/templates/component.jinja2
-//
-// Design System: sandbox
-// Version: v0_9_0
-// Audience: 1p
 
 package androidx.compose.material3.tokens
 
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index dffb7ff..0c5d73d 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -151,7 +151,7 @@
     method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public void recordSideEffect(kotlin.jvm.functions.Function0 effect);
     method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public void recordUsed(androidx.compose.runtime.RecomposeScope scope);
     method @androidx.compose.runtime.ComposeCompilerApi public Object? rememberedValue();
-    method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public boolean shouldExecute(boolean parametersChanged);
+    method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public boolean shouldExecute(boolean parametersChanged, int flags);
     method @androidx.compose.runtime.ComposeCompilerApi public void skipCurrentGroup();
     method @androidx.compose.runtime.ComposeCompilerApi public void skipToGroupEnd();
     method public void sourceInformation(String sourceInformation);
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 9c343f0..11909a2 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -156,7 +156,7 @@
     method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public void recordSideEffect(kotlin.jvm.functions.Function0 effect);
     method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public void recordUsed(androidx.compose.runtime.RecomposeScope scope);
     method @androidx.compose.runtime.ComposeCompilerApi public Object? rememberedValue();
-    method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public boolean shouldExecute(boolean parametersChanged);
+    method @SuppressCompatibility @androidx.compose.runtime.InternalComposeApi public boolean shouldExecute(boolean parametersChanged, int flags);
     method @androidx.compose.runtime.ComposeCompilerApi public void skipCurrentGroup();
     method @androidx.compose.runtime.ComposeCompilerApi public void skipToGroupEnd();
     method public void sourceInformation(String sourceInformation);
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 0e48726..28f2850 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -985,7 +985,7 @@
      * execute (such as its scope was invalidated or a static composition local it was changed) or
      * the composition is pausable and the composition is pausing.
      */
-    @InternalComposeApi fun shouldExecute(parametersChanged: Boolean): Boolean
+    @InternalComposeApi fun shouldExecute(parametersChanged: Boolean, flags: Int): Boolean
 
     // Internal API
 
@@ -3038,7 +3038,8 @@
     }
 
     @ComposeCompilerApi
-    override fun shouldExecute(parametersChanged: Boolean): Boolean {
+    @Suppress("UNUSED")
+    override fun shouldExecute(parametersChanged: Boolean, flags: Int): Boolean {
         return parametersChanged || !skipping
     }
 
diff --git a/compose/ui/ui-util/api/current.txt b/compose/ui/ui-util/api/current.txt
index 216790ac..57823b5 100644
--- a/compose/ui/ui-util/api/current.txt
+++ b/compose/ui/ui-util/api/current.txt
@@ -66,10 +66,16 @@
     method public static float fastCbrt(float x);
     method public static inline double fastCoerceAtLeast(double, double minimumValue);
     method public static inline float fastCoerceAtLeast(float, float minimumValue);
+    method public static inline int fastCoerceAtLeast(int, int minimumValue);
+    method public static inline long fastCoerceAtLeast(long, long minimumValue);
     method public static inline double fastCoerceAtMost(double, double maximumValue);
     method public static inline float fastCoerceAtMost(float, float maximumValue);
+    method public static inline int fastCoerceAtMost(int, int maximumValue);
+    method public static inline long fastCoerceAtMost(long, long maximumValue);
     method public static inline double fastCoerceIn(double, double minimumValue, double maximumValue);
     method public static inline float fastCoerceIn(float, float minimumValue, float maximumValue);
+    method public static inline int fastCoerceIn(int, int minimumValue, int maximumValue);
+    method public static inline long fastCoerceIn(long, long minimumValue, long maximumValue);
     method public static inline boolean fastIsFinite(double);
     method public static inline boolean fastIsFinite(float);
     method public static inline float fastMaxOf(float a, float b, float c, float d);
diff --git a/compose/ui/ui-util/api/restricted_current.txt b/compose/ui/ui-util/api/restricted_current.txt
index 216790ac..57823b5 100644
--- a/compose/ui/ui-util/api/restricted_current.txt
+++ b/compose/ui/ui-util/api/restricted_current.txt
@@ -66,10 +66,16 @@
     method public static float fastCbrt(float x);
     method public static inline double fastCoerceAtLeast(double, double minimumValue);
     method public static inline float fastCoerceAtLeast(float, float minimumValue);
+    method public static inline int fastCoerceAtLeast(int, int minimumValue);
+    method public static inline long fastCoerceAtLeast(long, long minimumValue);
     method public static inline double fastCoerceAtMost(double, double maximumValue);
     method public static inline float fastCoerceAtMost(float, float maximumValue);
+    method public static inline int fastCoerceAtMost(int, int maximumValue);
+    method public static inline long fastCoerceAtMost(long, long maximumValue);
     method public static inline double fastCoerceIn(double, double minimumValue, double maximumValue);
     method public static inline float fastCoerceIn(float, float minimumValue, float maximumValue);
+    method public static inline int fastCoerceIn(int, int minimumValue, int maximumValue);
+    method public static inline long fastCoerceIn(long, long minimumValue, long maximumValue);
     method public static inline boolean fastIsFinite(double);
     method public static inline boolean fastIsFinite(float);
     method public static inline float fastMaxOf(float a, float b, float c, float d);
diff --git a/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/MathHelpers.kt b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/MathHelpers.kt
index fa82086..ace3e1b 100644
--- a/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/MathHelpers.kt
+++ b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/MathHelpers.kt
@@ -93,6 +93,42 @@
 }
 
 /**
+ * Returns this integer value clamped in the inclusive range defined by [minimumValue] and
+ * [maximumValue]. Unlike [Int.coerceIn], the range is not validated: the caller must ensure that
+ * [minimumValue] is less than [maximumValue].
+ */
+inline fun Int.fastCoerceIn(minimumValue: Int, maximumValue: Int) =
+    this.fastCoerceAtLeast(minimumValue).fastCoerceAtMost(maximumValue)
+
+/** Ensures that this value is not less than the specified [minimumValue]. */
+inline fun Int.fastCoerceAtLeast(minimumValue: Int): Int {
+    return if (this < minimumValue) minimumValue else this
+}
+
+/** Ensures that this value is not greater than the specified [maximumValue]. */
+inline fun Int.fastCoerceAtMost(maximumValue: Int): Int {
+    return if (this > maximumValue) maximumValue else this
+}
+
+/**
+ * Returns this long value clamped in the inclusive range defined by [minimumValue] and
+ * [maximumValue]. Unlike [Long.coerceIn], the range is not validated: the caller must ensure that
+ * [minimumValue] is less than [maximumValue].
+ */
+inline fun Long.fastCoerceIn(minimumValue: Long, maximumValue: Long) =
+    this.fastCoerceAtLeast(minimumValue).fastCoerceAtMost(maximumValue)
+
+/** Ensures that this value is not less than the specified [minimumValue]. */
+inline fun Long.fastCoerceAtLeast(minimumValue: Long): Long {
+    return if (this < minimumValue) minimumValue else this
+}
+
+/** Ensures that this value is not greater than the specified [maximumValue]. */
+inline fun Long.fastCoerceAtMost(maximumValue: Long): Long {
+    return if (this > maximumValue) maximumValue else this
+}
+
+/**
  * Returns `true` if this float is a finite floating-point value; returns `false` otherwise (for
  * `NaN` and infinity).
  */
diff --git a/constraintlayout/constraintlayout-compose/api/1.1.0-beta01.txt b/constraintlayout/constraintlayout-compose/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..f9829bc
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/api/1.1.0-beta01.txt
@@ -0,0 +1,1013 @@
+// Signature format: 4.0
+package androidx.constraintlayout.compose {
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class Arc {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.Arc.Companion Companion;
+  }
+
+  public static final class Arc.Companion {
+    method public androidx.constraintlayout.compose.Arc getAbove();
+    method public androidx.constraintlayout.compose.Arc getBelow();
+    method public androidx.constraintlayout.compose.Arc getFlip();
+    method public androidx.constraintlayout.compose.Arc getNone();
+    method public androidx.constraintlayout.compose.Arc getStartHorizontal();
+    method public androidx.constraintlayout.compose.Arc getStartVertical();
+    property public final androidx.constraintlayout.compose.Arc Above;
+    property public final androidx.constraintlayout.compose.Arc Below;
+    property public final androidx.constraintlayout.compose.Arc Flip;
+    property public final androidx.constraintlayout.compose.Arc None;
+    property public final androidx.constraintlayout.compose.Arc StartHorizontal;
+    property public final androidx.constraintlayout.compose.Arc StartVertical;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public abstract sealed class BaseKeyFrameScope {
+    method protected final  kotlin.properties.ObservableProperty addNameOnPropertyChange(E initialValue, optional String? nameOverride);
+    method protected final  kotlin.properties.ObservableProperty addOnPropertyChange(T initialValue, optional String? nameOverride);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public abstract sealed class BaseKeyFramesScope {
+    method public final androidx.constraintlayout.compose.Easing getEasing();
+    method public final void setEasing(androidx.constraintlayout.compose.Easing);
+    property public final androidx.constraintlayout.compose.Easing easing;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface BaselineAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor anchor, optional float margin, optional float goneMargin);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChainStyle {
+    field public static final androidx.constraintlayout.compose.ChainStyle.Companion Companion;
+  }
+
+  public static final class ChainStyle.Companion {
+    method @androidx.compose.runtime.Stable public androidx.constraintlayout.compose.ChainStyle Packed(float bias);
+    method public androidx.constraintlayout.compose.ChainStyle getPacked();
+    method public androidx.constraintlayout.compose.ChainStyle getSpread();
+    method public androidx.constraintlayout.compose.ChainStyle getSpreadInside();
+    property public final androidx.constraintlayout.compose.ChainStyle Packed;
+    property public final androidx.constraintlayout.compose.ChainStyle Spread;
+    property public final androidx.constraintlayout.compose.ChainStyle SpreadInside;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class ConstrainScope {
+    method public androidx.constraintlayout.compose.Dimension asDimension(float);
+    method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor);
+    method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor);
+    method public void centerHorizontallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void centerTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other);
+    method public void centerVerticallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void circular(androidx.constraintlayout.compose.ConstrainedLayoutReference other, float angle, float distance);
+    method public void clearConstraints();
+    method public void clearHorizontal();
+    method public void clearVertical();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
+    method public float getAlpha();
+    method public androidx.constraintlayout.compose.BaselineAnchorable getBaseline();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
+    method public androidx.constraintlayout.compose.Dimension getHeight();
+    method public float getHorizontalBias();
+    method public float getHorizontalChainWeight();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getStart();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getTop();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public float getVerticalBias();
+    method public float getVerticalChainWeight();
+    method public androidx.constraintlayout.compose.Visibility getVisibility();
+    method public androidx.constraintlayout.compose.Dimension getWidth();
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom, optional float topMargin, optional float bottomMargin, optional float topGoneMargin, optional float bottomGoneMargin, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom, optional float startMargin, optional float topMargin, optional float endMargin, optional float bottomMargin, optional float startGoneMargin, optional float topGoneMargin, optional float endGoneMargin, optional float bottomGoneMargin, optional @FloatRange(from=0.0, to=1.0) float horizontalBias, optional @FloatRange(from=0.0, to=1.0) float verticalBias);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end, optional float startMargin, optional float endMargin, optional float startGoneMargin, optional float endGoneMargin, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void resetDimensions();
+    method public void resetTransforms();
+    method public void setAlpha(float);
+    method public void setHeight(androidx.constraintlayout.compose.Dimension);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalChainWeight(float);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public void setVerticalBias(float);
+    method public void setVerticalChainWeight(float);
+    method public void setVisibility(androidx.constraintlayout.compose.Visibility);
+    method public void setWidth(androidx.constraintlayout.compose.Dimension);
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteLeft;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteRight;
+    property public final float alpha;
+    property public final androidx.constraintlayout.compose.BaselineAnchorable baseline;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable bottom;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable end;
+    property public final androidx.constraintlayout.compose.Dimension height;
+    property public final float horizontalBias;
+    property public final float horizontalChainWeight;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable start;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable top;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+    property public final float verticalBias;
+    property public final float verticalChainWeight;
+    property public final androidx.constraintlayout.compose.Visibility visibility;
+    property public final androidx.constraintlayout.compose.Dimension width;
+  }
+
+  @androidx.compose.runtime.Stable public final class ConstrainedLayoutReference extends androidx.constraintlayout.compose.LayoutReference {
+    ctor public ConstrainedLayoutReference(Object id);
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteRight();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor getBaseline();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getBottom();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getEnd();
+    method public Object getId();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getStart();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getTop();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteLeft;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteRight;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor baseline;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end;
+    property public Object id;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top;
+  }
+
+  public abstract class ConstraintLayoutBaseScope {
+    ctor public ConstraintLayoutBaseScope();
+    method public final void applyTo(androidx.constraintlayout.compose.State state);
+    method public final androidx.constraintlayout.compose.ConstrainScope constrain(androidx.constraintlayout.compose.ConstrainedLayoutReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final void constrain(androidx.constraintlayout.compose.ConstrainedLayoutReference[] refs, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.HorizontalChainScope constrain(androidx.constraintlayout.compose.HorizontalChainReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.VerticalChainScope constrain(androidx.constraintlayout.compose.VerticalChainReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createAbsoluteLeftBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createAbsoluteRightBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createBottomBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createColumn(androidx.constraintlayout.compose.LayoutReference[] elements, optional float spacing, optional float[] weights);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createEndBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float padding, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float paddingHorizontal, optional float paddingVertical, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float paddingLeft, optional float paddingTop, optional float paddingRight, optional float paddingBottom, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createGrid(androidx.constraintlayout.compose.LayoutReference[] elements, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns, optional boolean isHorizontalArrangement, optional float verticalSpacing, optional float horizontalSpacing, optional float[] rowWeights, optional float[] columnWeights, optional androidx.constraintlayout.compose.Skip[] skips, optional androidx.constraintlayout.compose.Span[] spans, optional int flags);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteLeft(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteLeft(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteRight(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteRight(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromBottom(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromBottom(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromEnd(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromEnd(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromStart(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromStart(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromTop(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromTop(float fraction);
+    method public final androidx.constraintlayout.compose.HorizontalChainReference createHorizontalChain(androidx.constraintlayout.compose.LayoutReference[] elements, optional androidx.constraintlayout.compose.ChainStyle chainStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createRow(androidx.constraintlayout.compose.LayoutReference[] elements, optional float spacing, optional float[] weights);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createStartBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createTopBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.VerticalChainReference createVerticalChain(androidx.constraintlayout.compose.LayoutReference[] elements, optional androidx.constraintlayout.compose.ChainStyle chainStyle);
+    method @Deprecated protected final java.util.List> getTasks();
+    method public void reset();
+    method public final androidx.constraintlayout.compose.LayoutReference withChainParams(androidx.constraintlayout.compose.LayoutReference, optional float startMargin, optional float topMargin, optional float endMargin, optional float bottomMargin, optional float startGoneMargin, optional float topGoneMargin, optional float endGoneMargin, optional float bottomGoneMargin, optional float weight);
+    method public final androidx.constraintlayout.compose.LayoutReference withHorizontalChainParams(androidx.constraintlayout.compose.LayoutReference, optional float startMargin, optional float endMargin, optional float startGoneMargin, optional float endGoneMargin, optional float weight);
+    method public final androidx.constraintlayout.compose.LayoutReference withVerticalChainParams(androidx.constraintlayout.compose.LayoutReference, optional float topMargin, optional float bottomMargin, optional float topGoneMargin, optional float bottomGoneMargin, optional float weight);
+    property @Deprecated protected final java.util.List> tasks;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.BaselineAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component2();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor copy(Object id, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.HorizontalAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component3();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor copy(Object id, int index, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.VerticalAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component3();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor copy(Object id, int index, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  public final class ConstraintLayoutKt {
+    method @androidx.compose.runtime.Composable public static inline void ConstraintLayout(optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional androidx.compose.animation.core.AnimationSpec? animateChangesSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function1 content);
+    method @Deprecated @androidx.compose.runtime.Composable public static inline void ConstraintLayout(optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional boolean animateChanges, optional androidx.compose.animation.core.AnimationSpec animationSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function1 content);
+    method @androidx.compose.runtime.Composable public static inline void ConstraintLayout(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional androidx.compose.animation.core.AnimationSpec? animateChangesSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function0 content);
+    method @Deprecated @androidx.compose.runtime.Composable public static inline void ConstraintLayout(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional boolean animateChanges, optional androidx.compose.animation.core.AnimationSpec animationSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function0 content);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(androidx.constraintlayout.compose.ConstraintSet extendConstraintSet, @org.intellij.lang.annotations.Language("json5") String jsonContent);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(androidx.constraintlayout.compose.ConstraintSet extendConstraintSet, kotlin.jvm.functions.Function1 description);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(@org.intellij.lang.annotations.Language("json5") String jsonContent);
+    method @androidx.compose.runtime.Composable public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(@org.intellij.lang.annotations.Language("json5") String content, optional @org.intellij.lang.annotations.Language("json5") String? overrideVariables);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(kotlin.jvm.functions.Function1 description);
+    method public static androidx.constraintlayout.compose.Dimension.MaxCoercible atLeast(androidx.constraintlayout.compose.Dimension.Coercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension atLeast(androidx.constraintlayout.compose.Dimension.MinCoercible, float dp);
+    method @Deprecated public static androidx.constraintlayout.compose.Dimension atLeastWrapContent(androidx.constraintlayout.compose.Dimension.MinCoercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension.MinCoercible atMost(androidx.constraintlayout.compose.Dimension.Coercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension atMost(androidx.constraintlayout.compose.Dimension.MaxCoercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension.MaxCoercible getAtLeastWrapContent(androidx.constraintlayout.compose.Dimension.Coercible);
+    method public static androidx.constraintlayout.compose.Dimension getAtLeastWrapContent(androidx.constraintlayout.compose.Dimension.MinCoercible);
+    method public static androidx.constraintlayout.compose.Dimension.MinCoercible getAtMostWrapContent(androidx.constraintlayout.compose.Dimension.Coercible);
+    method public static androidx.constraintlayout.compose.Dimension getAtMostWrapContent(androidx.constraintlayout.compose.Dimension.MaxCoercible);
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker public final class ConstraintLayoutScope extends androidx.constraintlayout.compose.ConstraintLayoutBaseScope {
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier constrainAs(androidx.compose.ui.Modifier, androidx.constraintlayout.compose.ConstrainedLayoutReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRef();
+    method @androidx.compose.runtime.Stable public androidx.constraintlayout.compose.ConstraintLayoutScope.ConstrainedLayoutReferences createRefs();
+  }
+
+  public final class ConstraintLayoutScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  public final class ConstraintLayoutTagKt {
+    method public static Object? getConstraintLayoutId(androidx.compose.ui.layout.Measurable);
+    method public static Object? getConstraintLayoutTag(androidx.compose.ui.layout.Measurable);
+    method public static androidx.compose.ui.Modifier layoutId(androidx.compose.ui.Modifier, String layoutId, optional String? tag);
+  }
+
+  public interface ConstraintLayoutTagParentData {
+    method public String getConstraintLayoutId();
+    method public String getConstraintLayoutTag();
+    property public abstract String constraintLayoutId;
+    property public abstract String constraintLayoutTag;
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmDefaultWithCompatibility public interface ConstraintSet {
+    method public void applyTo(androidx.constraintlayout.compose.State state, java.util.List measurables);
+    method public default void applyTo(androidx.constraintlayout.core.state.Transition transition, int type);
+    method public default boolean isDirty(java.util.List measurables);
+    method public default androidx.constraintlayout.compose.ConstraintSet override(String name, float value);
+  }
+
+  public final class ConstraintSetRef {
+    method public androidx.constraintlayout.compose.ConstraintSetRef copy(String name);
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker public final class ConstraintSetScope extends androidx.constraintlayout.compose.ConstraintLayoutBaseScope {
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public androidx.constraintlayout.compose.ConstraintSetScope.ConstrainedLayoutReferences createRefsFor(java.lang.Object... ids);
+  }
+
+  public final class ConstraintSetScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class CurveFit {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.CurveFit.Companion Companion;
+  }
+
+  public static final class CurveFit.Companion {
+    method public androidx.constraintlayout.compose.CurveFit getLinear();
+    method public androidx.constraintlayout.compose.CurveFit getSpline();
+    property public final androidx.constraintlayout.compose.CurveFit Linear;
+    property public final androidx.constraintlayout.compose.CurveFit Spline;
+  }
+
+  @kotlin.jvm.JvmInline public final value class DebugFlags {
+    ctor public DebugFlags(optional boolean showBounds, optional boolean showPaths, optional boolean showKeyPositions);
+    method public boolean getShowBounds();
+    method public boolean getShowKeyPositions();
+    method public boolean getShowPaths();
+    property public final boolean showBounds;
+    property public final boolean showKeyPositions;
+    property public final boolean showPaths;
+    field public static final androidx.constraintlayout.compose.DebugFlags.Companion Companion;
+  }
+
+  public static final class DebugFlags.Companion {
+    method public int getAll();
+    method public int getNone();
+    property public final int All;
+    property public final int None;
+  }
+
+  public final class DesignElements {
+    method public void define(String name, kotlin.jvm.functions.Function2,kotlin.Unit> function);
+    method public java.util.HashMap,kotlin.Unit>> getMap();
+    method public void setMap(java.util.HashMap,kotlin.Unit>>);
+    property public final java.util.HashMap,kotlin.Unit>> map;
+    field public static final androidx.constraintlayout.compose.DesignElements INSTANCE;
+  }
+
+  public interface DesignInfoProvider {
+    method public String getDesignInfo(int startX, int startY, String args);
+  }
+
+  public interface Dimension {
+    field public static final androidx.constraintlayout.compose.Dimension.Companion Companion;
+  }
+
+  public static interface Dimension.Coercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  public static final class Dimension.Companion {
+    method public androidx.constraintlayout.compose.Dimension.Coercible getFillToConstraints();
+    method public androidx.constraintlayout.compose.Dimension getMatchParent();
+    method public androidx.constraintlayout.compose.Dimension.Coercible getPreferredWrapContent();
+    method public androidx.constraintlayout.compose.Dimension getWrapContent();
+    method public androidx.constraintlayout.compose.Dimension percent(float percent);
+    method public androidx.constraintlayout.compose.Dimension.MinCoercible preferredValue(float dp);
+    method public androidx.constraintlayout.compose.Dimension ratio(String ratio);
+    method public androidx.constraintlayout.compose.Dimension value(float dp);
+    property public final androidx.constraintlayout.compose.Dimension.Coercible fillToConstraints;
+    property public final androidx.constraintlayout.compose.Dimension matchParent;
+    property public final androidx.constraintlayout.compose.Dimension.Coercible preferredWrapContent;
+    property public final androidx.constraintlayout.compose.Dimension wrapContent;
+  }
+
+  public static interface Dimension.MaxCoercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  public static interface Dimension.MinCoercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class Easing {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.Easing.Companion Companion;
+  }
+
+  public static final class Easing.Companion {
+    method public androidx.constraintlayout.compose.Easing cubic(float x1, float y1, float x2, float y2);
+    method public androidx.constraintlayout.compose.Easing getAccelerate();
+    method public androidx.constraintlayout.compose.Easing getAnticipate();
+    method public androidx.constraintlayout.compose.Easing getDecelerate();
+    method public androidx.constraintlayout.compose.Easing getLinear();
+    method public androidx.constraintlayout.compose.Easing getOvershoot();
+    method public androidx.constraintlayout.compose.Easing getStandard();
+    property public final androidx.constraintlayout.compose.Easing Accelerate;
+    property public final androidx.constraintlayout.compose.Easing Anticipate;
+    property public final androidx.constraintlayout.compose.Easing Decelerate;
+    property public final androidx.constraintlayout.compose.Easing Linear;
+    property public final androidx.constraintlayout.compose.Easing Overshoot;
+    property public final androidx.constraintlayout.compose.Easing Standard;
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="MotionLayout API is experimental and it is likely to change.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMotionApi {
+  }
+
+  @androidx.compose.runtime.Immutable public final class FlowStyle {
+    field public static final androidx.constraintlayout.compose.FlowStyle.Companion Companion;
+  }
+
+  public static final class FlowStyle.Companion {
+    method public androidx.constraintlayout.compose.FlowStyle getPacked();
+    method public androidx.constraintlayout.compose.FlowStyle getSpread();
+    method public androidx.constraintlayout.compose.FlowStyle getSpreadInside();
+    property public final androidx.constraintlayout.compose.FlowStyle Packed;
+    property public final androidx.constraintlayout.compose.FlowStyle Spread;
+    property public final androidx.constraintlayout.compose.FlowStyle SpreadInside;
+  }
+
+  @kotlin.jvm.JvmInline public final value class GridFlag {
+    method public boolean isPlaceLayoutsOnSpansFirst();
+    method public infix int or(int other);
+    property public final boolean isPlaceLayoutsOnSpansFirst;
+    field public static final androidx.constraintlayout.compose.GridFlag.Companion Companion;
+  }
+
+  public static final class GridFlag.Companion {
+    method public int getNone();
+    method public int getPlaceLayoutsOnSpansFirst();
+    property public final int None;
+    property public final int PlaceLayoutsOnSpansFirst;
+  }
+
+  @androidx.compose.runtime.Immutable public final class HorizontalAlign {
+    field public static final androidx.constraintlayout.compose.HorizontalAlign.Companion Companion;
+  }
+
+  public static final class HorizontalAlign.Companion {
+    method public androidx.constraintlayout.compose.HorizontalAlign getCenter();
+    method public androidx.constraintlayout.compose.HorizontalAlign getEnd();
+    method public androidx.constraintlayout.compose.HorizontalAlign getStart();
+    property public final androidx.constraintlayout.compose.HorizontalAlign Center;
+    property public final androidx.constraintlayout.compose.HorizontalAlign End;
+    property public final androidx.constraintlayout.compose.HorizontalAlign Start;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface HorizontalAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor anchor, optional float margin, optional float goneMargin);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Stable public final class HorizontalChainReference extends androidx.constraintlayout.compose.LayoutReference {
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteRight();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getEnd();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getStart();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteLeft;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteRight;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class HorizontalChainScope {
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getStart();
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteLeft;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteRight;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable end;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable start;
+  }
+
+  public final class InvalidationStrategy {
+    ctor public InvalidationStrategy(optional kotlin.jvm.functions.Function3? onIncomingConstraints, kotlin.jvm.functions.Function0? onObservedStateChange);
+    method public kotlin.jvm.functions.Function3? getOnIncomingConstraints();
+    method public kotlin.jvm.functions.Function0? getOnObservedStateChange();
+    property public final kotlin.jvm.functions.Function3? onIncomingConstraints;
+    property public final kotlin.jvm.functions.Function0? onObservedStateChange;
+    field public static final androidx.constraintlayout.compose.InvalidationStrategy.Companion Companion;
+  }
+
+  public static final class InvalidationStrategy.Companion {
+    method public androidx.constraintlayout.compose.InvalidationStrategy getDefaultInvalidationStrategy();
+    property public final androidx.constraintlayout.compose.InvalidationStrategy DefaultInvalidationStrategy;
+  }
+
+  public final class InvalidationStrategySpecification {
+    method public boolean shouldInvalidateOnFixedHeight(long oldConstraints, long newConstraints, int skipCount, int threshold);
+    method public boolean shouldInvalidateOnFixedWidth(long oldConstraints, long newConstraints, int skipCount, int threshold);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyAttributeScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public float getAlpha();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public void setAlpha(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    property public final float alpha;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyAttributesScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyCycleScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public float getAlpha();
+    method public float getOffset();
+    method public float getPeriod();
+    method public float getPhase();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public void setAlpha(float);
+    method public void setOffset(float);
+    method public void setPeriod(float);
+    method public void setPhase(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    property public final float alpha;
+    property public final float offset;
+    property public final float period;
+    property public final float phase;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyCyclesScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyPositionScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public androidx.constraintlayout.compose.CurveFit? getCurveFit();
+    method public float getPercentHeight();
+    method public float getPercentWidth();
+    method public float getPercentX();
+    method public float getPercentY();
+    method public void setCurveFit(androidx.constraintlayout.compose.CurveFit?);
+    method public void setPercentHeight(float);
+    method public void setPercentWidth(float);
+    method public void setPercentX(float);
+    method public void setPercentY(float);
+    property public final androidx.constraintlayout.compose.CurveFit? curveFit;
+    property public final float percentHeight;
+    property public final float percentWidth;
+    property public final float percentX;
+    property public final float percentY;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyPositionsScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+    method public androidx.constraintlayout.compose.RelativePosition getType();
+    method public void setType(androidx.constraintlayout.compose.RelativePosition);
+    property public final androidx.constraintlayout.compose.RelativePosition type;
+  }
+
+  public enum LayoutInfoFlags {
+    enum_constant public static final androidx.constraintlayout.compose.LayoutInfoFlags BOUNDS;
+    enum_constant public static final androidx.constraintlayout.compose.LayoutInfoFlags NONE;
+  }
+
+  public interface LayoutInformationReceiver {
+    method public androidx.constraintlayout.compose.MotionLayoutDebugFlags getForcedDrawDebug();
+    method public int getForcedHeight();
+    method public float getForcedProgress();
+    method public int getForcedWidth();
+    method public androidx.constraintlayout.compose.LayoutInfoFlags getLayoutInformationMode();
+    method public void onNewProgress(float progress);
+    method public void resetForcedProgress();
+    method public void setLayoutInformation(String information);
+    method public void setUpdateFlag(androidx.compose.runtime.MutableState needsUpdate);
+  }
+
+  @androidx.compose.runtime.Stable public abstract class LayoutReference {
+  }
+
+  public final class MotionCarouselKt {
+    method @androidx.compose.runtime.Composable public static void ItemHolder(int i, String slotPrefix, boolean showSlot, kotlin.jvm.functions.Function0 function);
+    method @androidx.compose.runtime.Composable public static void MotionCarousel(androidx.constraintlayout.compose.MotionScene motionScene, int initialSlotIndex, int numSlots, optional String backwardTransition, optional String forwardTransition, optional String slotPrefix, optional boolean showSlots, kotlin.jvm.functions.Function1 content);
+    method public static inline  void items(androidx.constraintlayout.compose.MotionCarouselScope, java.util.List items, kotlin.jvm.functions.Function1 itemContent);
+    method public static inline  void itemsWithProperties(androidx.constraintlayout.compose.MotionCarouselScope, java.util.List items, kotlin.jvm.functions.Function2,kotlin.Unit> itemContent);
+  }
+
+  public interface MotionCarouselScope {
+    method public void items(int count, kotlin.jvm.functions.Function1 itemContent);
+    method public void itemsWithProperties(int count, kotlin.jvm.functions.Function2,kotlin.Unit> itemContent);
+  }
+
+  public interface MotionItemsProvider {
+    method public int count();
+    method public kotlin.jvm.functions.Function0 getContent(int index);
+    method public kotlin.jvm.functions.Function0 getContent(int index, androidx.compose.runtime.State properties);
+    method public boolean hasItemsWithProperties();
+  }
+
+  public enum MotionLayoutDebugFlags {
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags NONE;
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags SHOW_ALL;
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags UNKNOWN;
+  }
+
+  @Deprecated public enum MotionLayoutFlag {
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
+  }
+
+  public final class MotionLayoutKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, float progress, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, float progress, optional androidx.compose.ui.Modifier modifier, optional String transitionName, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, String? constraintSetName, androidx.compose.animation.core.AnimationSpec animationSpec, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0? finishedAnimationListener, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class MotionLayoutScope {
+    method public long customColor(String id, String name);
+    method public float customDistance(String id, String name);
+    method public float customFloat(String id, String name);
+    method public long customFontSize(String id, String name);
+    method public int customInt(String id, String name);
+    method public androidx.constraintlayout.compose.MotionLayoutScope.CustomProperties customProperties(String id);
+    method @Deprecated public long motionColor(String id, String name);
+    method @Deprecated public float motionDistance(String id, String name);
+    method @Deprecated public float motionFloat(String id, String name);
+    method @Deprecated public long motionFontSize(String id, String name);
+    method @Deprecated public int motionInt(String id, String name);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.runtime.State motionProperties(String id);
+    method @Deprecated public androidx.constraintlayout.compose.MotionLayoutScope.MotionProperties motionProperties(String id, String tag);
+    method public androidx.compose.ui.Modifier onStartEndBoundsChanged(androidx.compose.ui.Modifier, Object layoutId, kotlin.jvm.functions.Function2 onBoundsChanged);
+  }
+
+  public final class MotionLayoutScope.CustomProperties {
+    method public long color(String name);
+    method public float distance(String name);
+    method public float float(String name);
+    method public long fontSize(String name);
+    method public int int(String name);
+  }
+
+  public final class MotionLayoutScope.MotionProperties {
+    method public long color(String name);
+    method public float distance(String name);
+    method public float float(String name);
+    method public long fontSize(String name);
+    method public String id();
+    method public int int(String name);
+    method public String? tag();
+  }
+
+  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.constraintlayout.compose.ExperimentalMotionApi public interface MotionScene extends androidx.constraintlayout.core.state.CoreMotionScene {
+    method public androidx.constraintlayout.compose.ConstraintSet? getConstraintSetInstance(String name);
+    method public androidx.constraintlayout.compose.Transition? getTransitionInstance(String name);
+  }
+
+  public final class MotionSceneKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.MotionScene MotionScene(@org.intellij.lang.annotations.Language("json5") String content);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class MotionSceneScope {
+    method public androidx.constraintlayout.compose.ConstraintSetRef addConstraintSet(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional String? name);
+    method public void addTransition(androidx.constraintlayout.compose.Transition transition, optional String? name);
+    method public androidx.constraintlayout.compose.ConstraintSetRef constraintSet(optional String? name, optional androidx.constraintlayout.compose.ConstraintSetRef? extendConstraintSet, kotlin.jvm.functions.Function1 constraintSetContent);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public androidx.constraintlayout.compose.MotionSceneScope.ConstrainedLayoutReferences createRefsFor(java.lang.Object... ids);
+    method public void customColor(androidx.constraintlayout.compose.ConstrainScope, String name, long value);
+    method public void customColor(androidx.constraintlayout.compose.KeyAttributeScope, String name, long value);
+    method public void customDistance(androidx.constraintlayout.compose.ConstrainScope, String name, float value);
+    method public void customDistance(androidx.constraintlayout.compose.KeyAttributeScope, String name, float value);
+    method public void customFloat(androidx.constraintlayout.compose.ConstrainScope, String name, float value);
+    method public void customFloat(androidx.constraintlayout.compose.KeyAttributeScope, String name, float value);
+    method public void customFontSize(androidx.constraintlayout.compose.ConstrainScope, String name, long value);
+    method public void customFontSize(androidx.constraintlayout.compose.KeyAttributeScope, String name, long value);
+    method public void customInt(androidx.constraintlayout.compose.ConstrainScope, String name, int value);
+    method public void customInt(androidx.constraintlayout.compose.KeyAttributeScope, String name, int value);
+    method public void defaultTransition(androidx.constraintlayout.compose.ConstraintSetRef from, androidx.constraintlayout.compose.ConstraintSetRef to, optional kotlin.jvm.functions.Function1 transitionContent);
+    method public float getStaggeredWeight(androidx.constraintlayout.compose.ConstrainScope);
+    method public void setStaggeredWeight(androidx.constraintlayout.compose.ConstrainScope, float);
+    method public void transition(androidx.constraintlayout.compose.ConstraintSetRef from, androidx.constraintlayout.compose.ConstraintSetRef to, optional String? name, kotlin.jvm.functions.Function1 transitionContent);
+  }
+
+  public final class MotionSceneScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  public final class MotionSceneScopeKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.MotionScene MotionScene(kotlin.jvm.functions.Function1 motionSceneContent);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class OnSwipe {
+    ctor public OnSwipe(androidx.constraintlayout.compose.ConstrainedLayoutReference anchor, androidx.constraintlayout.compose.SwipeSide side, androidx.constraintlayout.compose.SwipeDirection direction, optional float dragScale, optional float dragThreshold, optional androidx.constraintlayout.compose.ConstrainedLayoutReference? dragAround, optional androidx.constraintlayout.compose.ConstrainedLayoutReference? limitBoundsTo, optional androidx.constraintlayout.compose.SwipeTouchUp onTouchUp, optional androidx.constraintlayout.compose.SwipeMode mode);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getAnchor();
+    method public androidx.constraintlayout.compose.SwipeDirection getDirection();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference? getDragAround();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference? getLimitBoundsTo();
+    method public androidx.constraintlayout.compose.SwipeMode getMode();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getOnTouchUp();
+    method public androidx.constraintlayout.compose.SwipeSide getSide();
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference anchor;
+    property public final androidx.constraintlayout.compose.SwipeDirection direction;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference? dragAround;
+    property public final float dragScale;
+    property public final float dragThreshold;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference? limitBoundsTo;
+    property public final androidx.constraintlayout.compose.SwipeMode mode;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp onTouchUp;
+    property public final androidx.constraintlayout.compose.SwipeSide side;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class RelativePosition {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.RelativePosition.Companion Companion;
+  }
+
+  public static final class RelativePosition.Companion {
+    method public androidx.constraintlayout.compose.RelativePosition getDelta();
+    method public androidx.constraintlayout.compose.RelativePosition getParent();
+    method public androidx.constraintlayout.compose.RelativePosition getPath();
+    property public final androidx.constraintlayout.compose.RelativePosition Delta;
+    property public final androidx.constraintlayout.compose.RelativePosition Parent;
+    property public final androidx.constraintlayout.compose.RelativePosition Path;
+  }
+
+  @kotlin.jvm.JvmInline public final value class Skip {
+    ctor public Skip(@IntRange(from=0L) int position, @IntRange(from=1L) int size);
+    ctor public Skip(@IntRange(from=0L) int position, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns);
+    method public String getDescription();
+    property public final String description;
+  }
+
+  @kotlin.jvm.JvmInline public final value class Span {
+    ctor public Span(@IntRange(from=0L) int position, @IntRange(from=1L) int size);
+    ctor public Span(@IntRange(from=0L) int position, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns);
+    ctor public Span(String description);
+    method public String getDescription();
+    property public final String description;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SpringBoundary {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SpringBoundary.Companion Companion;
+  }
+
+  public static final class SpringBoundary.Companion {
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceBoth();
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceEnd();
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceStart();
+    method public androidx.constraintlayout.compose.SpringBoundary getOvershoot();
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceBoth;
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceEnd;
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceStart;
+    property public final androidx.constraintlayout.compose.SpringBoundary Overshoot;
+  }
+
+  public final class State extends androidx.constraintlayout.core.state.State {
+    ctor public State(androidx.compose.ui.unit.Density density);
+    method public androidx.compose.ui.unit.Density getDensity();
+    method @Deprecated public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
+    method public long getRootIncomingConstraints();
+    method @Deprecated public void setLayoutDirection(androidx.compose.ui.unit.LayoutDirection);
+    method public void setRootIncomingConstraints(long);
+    property public final androidx.compose.ui.unit.Density density;
+    property @Deprecated public final androidx.compose.ui.unit.LayoutDirection layoutDirection;
+    property public final long rootIncomingConstraints;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeDirection {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeDirection.Companion Companion;
+  }
+
+  public static final class SwipeDirection.Companion {
+    method public androidx.constraintlayout.compose.SwipeDirection getClockwise();
+    method public androidx.constraintlayout.compose.SwipeDirection getCounterclockwise();
+    method public androidx.constraintlayout.compose.SwipeDirection getDown();
+    method public androidx.constraintlayout.compose.SwipeDirection getEnd();
+    method public androidx.constraintlayout.compose.SwipeDirection getLeft();
+    method public androidx.constraintlayout.compose.SwipeDirection getRight();
+    method public androidx.constraintlayout.compose.SwipeDirection getStart();
+    method public androidx.constraintlayout.compose.SwipeDirection getUp();
+    property public final androidx.constraintlayout.compose.SwipeDirection Clockwise;
+    property public final androidx.constraintlayout.compose.SwipeDirection Counterclockwise;
+    property public final androidx.constraintlayout.compose.SwipeDirection Down;
+    property public final androidx.constraintlayout.compose.SwipeDirection End;
+    property public final androidx.constraintlayout.compose.SwipeDirection Left;
+    property public final androidx.constraintlayout.compose.SwipeDirection Right;
+    property public final androidx.constraintlayout.compose.SwipeDirection Start;
+    property public final androidx.constraintlayout.compose.SwipeDirection Up;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeMode {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeMode.Companion Companion;
+  }
+
+  public static final class SwipeMode.Companion {
+    method public androidx.constraintlayout.compose.SwipeMode getSpring();
+    method public androidx.constraintlayout.compose.SwipeMode getVelocity();
+    method public androidx.constraintlayout.compose.SwipeMode spring(optional float mass, optional float stiffness, optional float damping, optional float threshold, optional androidx.constraintlayout.compose.SpringBoundary boundary);
+    method public androidx.constraintlayout.compose.SwipeMode velocity(optional float maxVelocity, optional float maxAcceleration);
+    property public final androidx.constraintlayout.compose.SwipeMode Spring;
+    property public final androidx.constraintlayout.compose.SwipeMode Velocity;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeSide {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeSide.Companion Companion;
+  }
+
+  public static final class SwipeSide.Companion {
+    method public androidx.constraintlayout.compose.SwipeSide getBottom();
+    method public androidx.constraintlayout.compose.SwipeSide getEnd();
+    method public androidx.constraintlayout.compose.SwipeSide getLeft();
+    method public androidx.constraintlayout.compose.SwipeSide getMiddle();
+    method public androidx.constraintlayout.compose.SwipeSide getRight();
+    method public androidx.constraintlayout.compose.SwipeSide getStart();
+    method public androidx.constraintlayout.compose.SwipeSide getTop();
+    property public final androidx.constraintlayout.compose.SwipeSide Bottom;
+    property public final androidx.constraintlayout.compose.SwipeSide End;
+    property public final androidx.constraintlayout.compose.SwipeSide Left;
+    property public final androidx.constraintlayout.compose.SwipeSide Middle;
+    property public final androidx.constraintlayout.compose.SwipeSide Right;
+    property public final androidx.constraintlayout.compose.SwipeSide Start;
+    property public final androidx.constraintlayout.compose.SwipeSide Top;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeTouchUp {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeTouchUp.Companion Companion;
+  }
+
+  public static final class SwipeTouchUp.Companion {
+    method public androidx.constraintlayout.compose.SwipeTouchUp getAutoComplete();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getDecelerate();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getNeverCompleteEnd();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getNeverCompleteStart();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getStop();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getToEnd();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getToStart();
+    property public final androidx.constraintlayout.compose.SwipeTouchUp AutoComplete;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp Decelerate;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp NeverCompleteEnd;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp NeverCompleteStart;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp Stop;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp ToEnd;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp ToStart;
+  }
+
+  public final class ToolingUtilsKt {
+    method public static androidx.compose.ui.semantics.SemanticsPropertyKey getDesignInfoDataKey();
+    property public static final androidx.compose.ui.semantics.SemanticsPropertyKey DesignInfoDataKey;
+  }
+
+  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.constraintlayout.compose.ExperimentalMotionApi public interface Transition {
+    method public String getEndConstraintSetId();
+    method public String getStartConstraintSetId();
+  }
+
+  public final class TransitionKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.Transition Transition(@org.intellij.lang.annotations.Language("json5") String content);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class TransitionScope {
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public float getMaxStaggerDelay();
+    method public androidx.constraintlayout.compose.Arc getMotionArc();
+    method public androidx.constraintlayout.compose.OnSwipe? getOnSwipe();
+    method public void keyAttributes(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyAttributesContent);
+    method public void keyCycles(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyCyclesContent);
+    method public void keyPositions(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyPositionsContent);
+    method public void setMaxStaggerDelay(float);
+    method public void setMotionArc(androidx.constraintlayout.compose.Arc);
+    method public void setOnSwipe(androidx.constraintlayout.compose.OnSwipe?);
+    property public final float maxStaggerDelay;
+    property public final androidx.constraintlayout.compose.Arc motionArc;
+    property public final androidx.constraintlayout.compose.OnSwipe? onSwipe;
+  }
+
+  public final class TransitionScopeKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.Transition Transition(optional String from, optional String to, kotlin.jvm.functions.Function1 content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class VerticalAlign {
+    field public static final androidx.constraintlayout.compose.VerticalAlign.Companion Companion;
+  }
+
+  public static final class VerticalAlign.Companion {
+    method public androidx.constraintlayout.compose.VerticalAlign getBaseline();
+    method public androidx.constraintlayout.compose.VerticalAlign getBottom();
+    method public androidx.constraintlayout.compose.VerticalAlign getCenter();
+    method public androidx.constraintlayout.compose.VerticalAlign getTop();
+    property public final androidx.constraintlayout.compose.VerticalAlign Baseline;
+    property public final androidx.constraintlayout.compose.VerticalAlign Bottom;
+    property public final androidx.constraintlayout.compose.VerticalAlign Center;
+    property public final androidx.constraintlayout.compose.VerticalAlign Top;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface VerticalAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Stable public final class VerticalChainReference extends androidx.constraintlayout.compose.LayoutReference {
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getBottom();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getTop();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class VerticalChainScope {
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getTop();
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable bottom;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable top;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Visibility {
+    field public static final androidx.constraintlayout.compose.Visibility.Companion Companion;
+  }
+
+  public static final class Visibility.Companion {
+    method public androidx.constraintlayout.compose.Visibility getGone();
+    method public androidx.constraintlayout.compose.Visibility getInvisible();
+    method public androidx.constraintlayout.compose.Visibility getVisible();
+    property public final androidx.constraintlayout.compose.Visibility Gone;
+    property public final androidx.constraintlayout.compose.Visibility Invisible;
+    property public final androidx.constraintlayout.compose.Visibility Visible;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Wrap {
+    field public static final androidx.constraintlayout.compose.Wrap.Companion Companion;
+  }
+
+  public static final class Wrap.Companion {
+    method public androidx.constraintlayout.compose.Wrap getAligned();
+    method public androidx.constraintlayout.compose.Wrap getChain();
+    method public androidx.constraintlayout.compose.Wrap getNone();
+    property public final androidx.constraintlayout.compose.Wrap Aligned;
+    property public final androidx.constraintlayout.compose.Wrap Chain;
+    property public final androidx.constraintlayout.compose.Wrap None;
+  }
+
+}
+
diff --git a/constraintlayout/constraintlayout-compose/api/res-1.1.0-beta01.txt b/constraintlayout/constraintlayout-compose/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/api/res-1.1.0-beta01.txt
diff --git a/constraintlayout/constraintlayout-compose/api/restricted_1.1.0-beta01.txt b/constraintlayout/constraintlayout-compose/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..f2836bb
--- /dev/null
+++ b/constraintlayout/constraintlayout-compose/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,1103 @@
+// Signature format: 4.0
+package androidx.constraintlayout.compose {
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class Arc {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.Arc.Companion Companion;
+  }
+
+  public static final class Arc.Companion {
+    method public androidx.constraintlayout.compose.Arc getAbove();
+    method public androidx.constraintlayout.compose.Arc getBelow();
+    method public androidx.constraintlayout.compose.Arc getFlip();
+    method public androidx.constraintlayout.compose.Arc getNone();
+    method public androidx.constraintlayout.compose.Arc getStartHorizontal();
+    method public androidx.constraintlayout.compose.Arc getStartVertical();
+    property public final androidx.constraintlayout.compose.Arc Above;
+    property public final androidx.constraintlayout.compose.Arc Below;
+    property public final androidx.constraintlayout.compose.Arc Flip;
+    property public final androidx.constraintlayout.compose.Arc None;
+    property public final androidx.constraintlayout.compose.Arc StartHorizontal;
+    property public final androidx.constraintlayout.compose.Arc StartVertical;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public abstract sealed class BaseKeyFrameScope {
+    method protected final  kotlin.properties.ObservableProperty addNameOnPropertyChange(E initialValue, optional String? nameOverride);
+    method protected final  kotlin.properties.ObservableProperty addOnPropertyChange(T initialValue, optional String? nameOverride);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public abstract sealed class BaseKeyFramesScope {
+    method public final androidx.constraintlayout.compose.Easing getEasing();
+    method public final void setEasing(androidx.constraintlayout.compose.Easing);
+    property public final androidx.constraintlayout.compose.Easing easing;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface BaselineAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor anchor, optional float margin, optional float goneMargin);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChainStyle {
+    field public static final androidx.constraintlayout.compose.ChainStyle.Companion Companion;
+  }
+
+  public static final class ChainStyle.Companion {
+    method @androidx.compose.runtime.Stable public androidx.constraintlayout.compose.ChainStyle Packed(float bias);
+    method public androidx.constraintlayout.compose.ChainStyle getPacked();
+    method public androidx.constraintlayout.compose.ChainStyle getSpread();
+    method public androidx.constraintlayout.compose.ChainStyle getSpreadInside();
+    property public final androidx.constraintlayout.compose.ChainStyle Packed;
+    property public final androidx.constraintlayout.compose.ChainStyle Spread;
+    property public final androidx.constraintlayout.compose.ChainStyle SpreadInside;
+  }
+
+  @kotlin.PublishedApi internal enum CompositionSource {
+    enum_constant public static final androidx.constraintlayout.compose.CompositionSource Content;
+    enum_constant public static final androidx.constraintlayout.compose.CompositionSource Unknown;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class ConstrainScope {
+    method public androidx.constraintlayout.compose.Dimension asDimension(float);
+    method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor);
+    method public void centerAround(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor);
+    method public void centerHorizontallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void centerTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other);
+    method public void centerVerticallyTo(androidx.constraintlayout.compose.ConstrainedLayoutReference other, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void circular(androidx.constraintlayout.compose.ConstrainedLayoutReference other, float angle, float distance);
+    method public void clearConstraints();
+    method public void clearHorizontal();
+    method public void clearVertical();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
+    method public float getAlpha();
+    method public androidx.constraintlayout.compose.BaselineAnchorable getBaseline();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
+    method public androidx.constraintlayout.compose.Dimension getHeight();
+    method public float getHorizontalBias();
+    method public float getHorizontalChainWeight();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getStart();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getTop();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public float getVerticalBias();
+    method public float getVerticalChainWeight();
+    method public androidx.constraintlayout.compose.Visibility getVisibility();
+    method public androidx.constraintlayout.compose.Dimension getWidth();
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom, optional float topMargin, optional float bottomMargin, optional float topGoneMargin, optional float bottomGoneMargin, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom, optional float startMargin, optional float topMargin, optional float endMargin, optional float bottomMargin, optional float startGoneMargin, optional float topGoneMargin, optional float endGoneMargin, optional float bottomGoneMargin, optional @FloatRange(from=0.0, to=1.0) float horizontalBias, optional @FloatRange(from=0.0, to=1.0) float verticalBias);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start, androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end, optional float startMargin, optional float endMargin, optional float startGoneMargin, optional float endGoneMargin, optional @FloatRange(from=0.0, to=1.0) float bias);
+    method public void resetDimensions();
+    method public void resetTransforms();
+    method public void setAlpha(float);
+    method public void setHeight(androidx.constraintlayout.compose.Dimension);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalChainWeight(float);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public void setVerticalBias(float);
+    method public void setVerticalChainWeight(float);
+    method public void setVisibility(androidx.constraintlayout.compose.Visibility);
+    method public void setWidth(androidx.constraintlayout.compose.Dimension);
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteLeft;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteRight;
+    property public final float alpha;
+    property public final androidx.constraintlayout.compose.BaselineAnchorable baseline;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable bottom;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable end;
+    property public final androidx.constraintlayout.compose.Dimension height;
+    property public final float horizontalBias;
+    property public final float horizontalChainWeight;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable start;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable top;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+    property public final float verticalBias;
+    property public final float verticalChainWeight;
+    property public final androidx.constraintlayout.compose.Visibility visibility;
+    property public final androidx.constraintlayout.compose.Dimension width;
+  }
+
+  @androidx.compose.runtime.Stable public final class ConstrainedLayoutReference extends androidx.constraintlayout.compose.LayoutReference {
+    ctor public ConstrainedLayoutReference(Object id);
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteRight();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor getBaseline();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getBottom();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getEnd();
+    method public Object getId();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getStart();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getTop();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteLeft;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteRight;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor baseline;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end;
+    property public Object id;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top;
+  }
+
+  public abstract class ConstraintLayoutBaseScope {
+    ctor public ConstraintLayoutBaseScope();
+    method public final void applyTo(androidx.constraintlayout.compose.State state);
+    method public final androidx.constraintlayout.compose.ConstrainScope constrain(androidx.constraintlayout.compose.ConstrainedLayoutReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final void constrain(androidx.constraintlayout.compose.ConstrainedLayoutReference[] refs, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.HorizontalChainScope constrain(androidx.constraintlayout.compose.HorizontalChainReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.VerticalChainScope constrain(androidx.constraintlayout.compose.VerticalChainReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createAbsoluteLeftBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createAbsoluteRightBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createBottomBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createColumn(androidx.constraintlayout.compose.LayoutReference[] elements, optional float spacing, optional float[] weights);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createEndBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float padding, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float paddingHorizontal, optional float paddingVertical, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createFlow(androidx.constraintlayout.compose.LayoutReference?[] elements, optional boolean flowVertically, optional float verticalGap, optional float horizontalGap, optional int maxElement, optional float paddingLeft, optional float paddingTop, optional float paddingRight, optional float paddingBottom, optional androidx.constraintlayout.compose.Wrap wrapMode, optional androidx.constraintlayout.compose.VerticalAlign verticalAlign, optional androidx.constraintlayout.compose.HorizontalAlign horizontalAlign, optional float horizontalFlowBias, optional float verticalFlowBias, optional androidx.constraintlayout.compose.FlowStyle verticalStyle, optional androidx.constraintlayout.compose.FlowStyle horizontalStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createGrid(androidx.constraintlayout.compose.LayoutReference[] elements, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns, optional boolean isHorizontalArrangement, optional float verticalSpacing, optional float horizontalSpacing, optional float[] rowWeights, optional float[] columnWeights, optional androidx.constraintlayout.compose.Skip[] skips, optional androidx.constraintlayout.compose.Span[] spans, optional int flags);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteLeft(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteLeft(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteRight(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromAbsoluteRight(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromBottom(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromBottom(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromEnd(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromEnd(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromStart(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createGuidelineFromStart(float fraction);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromTop(float offset);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createGuidelineFromTop(float fraction);
+    method public final androidx.constraintlayout.compose.HorizontalChainReference createHorizontalChain(androidx.constraintlayout.compose.LayoutReference[] elements, optional androidx.constraintlayout.compose.ChainStyle chainStyle);
+    method public final androidx.constraintlayout.compose.ConstrainedLayoutReference createRow(androidx.constraintlayout.compose.LayoutReference[] elements, optional float spacing, optional float[] weights);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor createStartBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor createTopBarrier(androidx.constraintlayout.compose.LayoutReference[] elements, optional float margin);
+    method public final androidx.constraintlayout.compose.VerticalChainReference createVerticalChain(androidx.constraintlayout.compose.LayoutReference[] elements, optional androidx.constraintlayout.compose.ChainStyle chainStyle);
+    method @Deprecated protected final java.util.List> getTasks();
+    method public void reset();
+    method public final androidx.constraintlayout.compose.LayoutReference withChainParams(androidx.constraintlayout.compose.LayoutReference, optional float startMargin, optional float topMargin, optional float endMargin, optional float bottomMargin, optional float startGoneMargin, optional float topGoneMargin, optional float endGoneMargin, optional float bottomGoneMargin, optional float weight);
+    method public final androidx.constraintlayout.compose.LayoutReference withHorizontalChainParams(androidx.constraintlayout.compose.LayoutReference, optional float startMargin, optional float endMargin, optional float startGoneMargin, optional float endGoneMargin, optional float weight);
+    method public final androidx.constraintlayout.compose.LayoutReference withVerticalChainParams(androidx.constraintlayout.compose.LayoutReference, optional float topMargin, optional float bottomMargin, optional float topGoneMargin, optional float bottomGoneMargin, optional float weight);
+    property @Deprecated protected final java.util.List> tasks;
+    field @kotlin.PublishedApi internal final androidx.constraintlayout.core.parser.CLObject containerObject;
+    field @kotlin.PublishedApi internal int helpersHashCode;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.BaselineAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component2();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor copy(Object id, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.HorizontalAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component3();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor copy(Object id, int index, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  @androidx.compose.runtime.Stable public static final class ConstraintLayoutBaseScope.VerticalAnchor {
+    method public androidx.constraintlayout.compose.LayoutReference component3();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor copy(Object id, int index, androidx.constraintlayout.compose.LayoutReference reference);
+    method public androidx.constraintlayout.compose.LayoutReference getReference();
+    property public final androidx.constraintlayout.compose.LayoutReference reference;
+  }
+
+  public final class ConstraintLayoutKt {
+    method @androidx.compose.runtime.Composable public static inline void ConstraintLayout(optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional androidx.compose.animation.core.AnimationSpec? animateChangesSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function1 content);
+    method @Deprecated @androidx.compose.runtime.Composable public static inline void ConstraintLayout(optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional boolean animateChanges, optional androidx.compose.animation.core.AnimationSpec animationSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function1 content);
+    method @androidx.compose.runtime.Composable public static inline void ConstraintLayout(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional androidx.compose.animation.core.AnimationSpec? animateChangesSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function0 content);
+    method @Deprecated @androidx.compose.runtime.Composable public static inline void ConstraintLayout(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional androidx.compose.ui.Modifier modifier, optional int optimizationLevel, optional boolean animateChanges, optional androidx.compose.animation.core.AnimationSpec animationSpec, optional kotlin.jvm.functions.Function0? finishedAnimationListener, kotlin.jvm.functions.Function0 content);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(androidx.constraintlayout.compose.ConstraintSet extendConstraintSet, @org.intellij.lang.annotations.Language("json5") String jsonContent);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(androidx.constraintlayout.compose.ConstraintSet extendConstraintSet, kotlin.jvm.functions.Function1 description);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(@org.intellij.lang.annotations.Language("json5") String jsonContent);
+    method @androidx.compose.runtime.Composable public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(@org.intellij.lang.annotations.Language("json5") String content, optional @org.intellij.lang.annotations.Language("json5") String? overrideVariables);
+    method public static androidx.constraintlayout.compose.ConstraintSet ConstraintSet(kotlin.jvm.functions.Function1 description);
+    method public static androidx.constraintlayout.compose.Dimension.MaxCoercible atLeast(androidx.constraintlayout.compose.Dimension.Coercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension atLeast(androidx.constraintlayout.compose.Dimension.MinCoercible, float dp);
+    method @Deprecated public static androidx.constraintlayout.compose.Dimension atLeastWrapContent(androidx.constraintlayout.compose.Dimension.MinCoercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension.MinCoercible atMost(androidx.constraintlayout.compose.Dimension.Coercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension atMost(androidx.constraintlayout.compose.Dimension.MaxCoercible, float dp);
+    method public static androidx.constraintlayout.compose.Dimension.MaxCoercible getAtLeastWrapContent(androidx.constraintlayout.compose.Dimension.Coercible);
+    method public static androidx.constraintlayout.compose.Dimension getAtLeastWrapContent(androidx.constraintlayout.compose.Dimension.MinCoercible);
+    method public static androidx.constraintlayout.compose.Dimension.MinCoercible getAtMostWrapContent(androidx.constraintlayout.compose.Dimension.Coercible);
+    method public static androidx.constraintlayout.compose.Dimension getAtMostWrapContent(androidx.constraintlayout.compose.Dimension.MaxCoercible);
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker public final class ConstraintLayoutScope extends androidx.constraintlayout.compose.ConstraintLayoutBaseScope {
+    ctor @kotlin.PublishedApi internal ConstraintLayoutScope();
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier constrainAs(androidx.compose.ui.Modifier, androidx.constraintlayout.compose.ConstrainedLayoutReference ref, kotlin.jvm.functions.Function1 constrainBlock);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRef();
+    method @androidx.compose.runtime.Stable public androidx.constraintlayout.compose.ConstraintLayoutScope.ConstrainedLayoutReferences createRefs();
+    field @kotlin.PublishedApi internal boolean isAnimateChanges;
+  }
+
+  public final class ConstraintLayoutScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  public final class ConstraintLayoutTagKt {
+    method public static Object? getConstraintLayoutId(androidx.compose.ui.layout.Measurable);
+    method public static Object? getConstraintLayoutTag(androidx.compose.ui.layout.Measurable);
+    method public static androidx.compose.ui.Modifier layoutId(androidx.compose.ui.Modifier, String layoutId, optional String? tag);
+  }
+
+  public interface ConstraintLayoutTagParentData {
+    method public String getConstraintLayoutId();
+    method public String getConstraintLayoutTag();
+    property public abstract String constraintLayoutId;
+    property public abstract String constraintLayoutTag;
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmDefaultWithCompatibility public interface ConstraintSet {
+    method public void applyTo(androidx.constraintlayout.compose.State state, java.util.List measurables);
+    method public default void applyTo(androidx.constraintlayout.core.state.Transition transition, int type);
+    method public default boolean isDirty(java.util.List measurables);
+    method public default androidx.constraintlayout.compose.ConstraintSet override(String name, float value);
+  }
+
+  @kotlin.PublishedApi internal final class ConstraintSetForInlineDsl implements androidx.constraintlayout.compose.ConstraintSet androidx.compose.runtime.RememberObserver {
+    ctor public ConstraintSetForInlineDsl(androidx.constraintlayout.compose.ConstraintLayoutScope scope);
+    method public void applyTo(androidx.constraintlayout.compose.State state, java.util.List measurables);
+    method public boolean getKnownDirty();
+    method public androidx.constraintlayout.compose.ConstraintLayoutScope getScope();
+    method public void onAbandoned();
+    method public void onForgotten();
+    method public void onRemembered();
+    method public void setKnownDirty(boolean);
+    property public final boolean knownDirty;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutScope scope;
+  }
+
+  public final class ConstraintSetRef {
+    method public androidx.constraintlayout.compose.ConstraintSetRef copy(String name);
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker public final class ConstraintSetScope extends androidx.constraintlayout.compose.ConstraintLayoutBaseScope {
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public androidx.constraintlayout.compose.ConstraintSetScope.ConstrainedLayoutReferences createRefsFor(java.lang.Object... ids);
+  }
+
+  public final class ConstraintSetScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class CurveFit {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.CurveFit.Companion Companion;
+  }
+
+  public static final class CurveFit.Companion {
+    method public androidx.constraintlayout.compose.CurveFit getLinear();
+    method public androidx.constraintlayout.compose.CurveFit getSpline();
+    property public final androidx.constraintlayout.compose.CurveFit Linear;
+    property public final androidx.constraintlayout.compose.CurveFit Spline;
+  }
+
+  @kotlin.jvm.JvmInline public final value class DebugFlags {
+    ctor public DebugFlags(optional boolean showBounds, optional boolean showPaths, optional boolean showKeyPositions);
+    method public boolean getShowBounds();
+    method public boolean getShowKeyPositions();
+    method public boolean getShowPaths();
+    property public final boolean showBounds;
+    property public final boolean showKeyPositions;
+    property public final boolean showPaths;
+    field public static final androidx.constraintlayout.compose.DebugFlags.Companion Companion;
+  }
+
+  public static final class DebugFlags.Companion {
+    method public int getAll();
+    method public int getNone();
+    property public final int All;
+    property public final int None;
+  }
+
+  public final class DesignElements {
+    method public void define(String name, kotlin.jvm.functions.Function2,kotlin.Unit> function);
+    method public java.util.HashMap,kotlin.Unit>> getMap();
+    method public void setMap(java.util.HashMap,kotlin.Unit>>);
+    property public final java.util.HashMap,kotlin.Unit>> map;
+    field public static final androidx.constraintlayout.compose.DesignElements INSTANCE;
+  }
+
+  public interface DesignInfoProvider {
+    method public String getDesignInfo(int startX, int startY, String args);
+  }
+
+  public interface Dimension {
+    field public static final androidx.constraintlayout.compose.Dimension.Companion Companion;
+  }
+
+  public static interface Dimension.Coercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  public static final class Dimension.Companion {
+    method public androidx.constraintlayout.compose.Dimension.Coercible getFillToConstraints();
+    method public androidx.constraintlayout.compose.Dimension getMatchParent();
+    method public androidx.constraintlayout.compose.Dimension.Coercible getPreferredWrapContent();
+    method public androidx.constraintlayout.compose.Dimension getWrapContent();
+    method public androidx.constraintlayout.compose.Dimension percent(float percent);
+    method public androidx.constraintlayout.compose.Dimension.MinCoercible preferredValue(float dp);
+    method public androidx.constraintlayout.compose.Dimension ratio(String ratio);
+    method public androidx.constraintlayout.compose.Dimension value(float dp);
+    property public final androidx.constraintlayout.compose.Dimension.Coercible fillToConstraints;
+    property public final androidx.constraintlayout.compose.Dimension matchParent;
+    property public final androidx.constraintlayout.compose.Dimension.Coercible preferredWrapContent;
+    property public final androidx.constraintlayout.compose.Dimension wrapContent;
+  }
+
+  public static interface Dimension.MaxCoercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  public static interface Dimension.MinCoercible extends androidx.constraintlayout.compose.Dimension {
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class Easing {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.Easing.Companion Companion;
+  }
+
+  public static final class Easing.Companion {
+    method public androidx.constraintlayout.compose.Easing cubic(float x1, float y1, float x2, float y2);
+    method public androidx.constraintlayout.compose.Easing getAccelerate();
+    method public androidx.constraintlayout.compose.Easing getAnticipate();
+    method public androidx.constraintlayout.compose.Easing getDecelerate();
+    method public androidx.constraintlayout.compose.Easing getLinear();
+    method public androidx.constraintlayout.compose.Easing getOvershoot();
+    method public androidx.constraintlayout.compose.Easing getStandard();
+    property public final androidx.constraintlayout.compose.Easing Accelerate;
+    property public final androidx.constraintlayout.compose.Easing Anticipate;
+    property public final androidx.constraintlayout.compose.Easing Decelerate;
+    property public final androidx.constraintlayout.compose.Easing Linear;
+    property public final androidx.constraintlayout.compose.Easing Overshoot;
+    property public final androidx.constraintlayout.compose.Easing Standard;
+  }
+
+  @kotlin.PublishedApi internal abstract class EditableJSONLayout implements androidx.constraintlayout.compose.LayoutInformationReceiver {
+    ctor public EditableJSONLayout(@org.intellij.lang.annotations.Language("json5") String content);
+    method public final String getCurrentContent();
+    method public final String? getDebugName();
+    method public androidx.constraintlayout.compose.MotionLayoutDebugFlags getForcedDrawDebug();
+    method public int getForcedHeight();
+    method public int getForcedWidth();
+    method public final String getLayoutInformation();
+    method public androidx.constraintlayout.compose.LayoutInfoFlags getLayoutInformationMode();
+    method protected final void initialization();
+    method protected final void onDrawDebug(int debugMode);
+    method protected final void onLayoutInformation(int mode);
+    method protected void onNewContent(String content);
+    method public final void onNewDimensions(int width, int height);
+    method public final void setCurrentContent(String content);
+    method public final void setDebugName(String? name);
+    method public void setLayoutInformation(String information);
+    method public void setUpdateFlag(androidx.compose.runtime.MutableState needsUpdate);
+    method protected final void signalUpdate();
+  }
+
+  @SuppressCompatibility @kotlin.RequiresOptIn(message="MotionLayout API is experimental and it is likely to change.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalMotionApi {
+  }
+
+  @androidx.compose.runtime.Immutable public final class FlowStyle {
+    field public static final androidx.constraintlayout.compose.FlowStyle.Companion Companion;
+  }
+
+  public static final class FlowStyle.Companion {
+    method public androidx.constraintlayout.compose.FlowStyle getPacked();
+    method public androidx.constraintlayout.compose.FlowStyle getSpread();
+    method public androidx.constraintlayout.compose.FlowStyle getSpreadInside();
+    property public final androidx.constraintlayout.compose.FlowStyle Packed;
+    property public final androidx.constraintlayout.compose.FlowStyle Spread;
+    property public final androidx.constraintlayout.compose.FlowStyle SpreadInside;
+  }
+
+  @kotlin.jvm.JvmInline public final value class GridFlag {
+    method public boolean isPlaceLayoutsOnSpansFirst();
+    method public infix int or(int other);
+    property public final boolean isPlaceLayoutsOnSpansFirst;
+    field public static final androidx.constraintlayout.compose.GridFlag.Companion Companion;
+  }
+
+  public static final class GridFlag.Companion {
+    method public int getNone();
+    method public int getPlaceLayoutsOnSpansFirst();
+    property public final int None;
+    property public final int PlaceLayoutsOnSpansFirst;
+  }
+
+  @androidx.compose.runtime.Immutable public final class HorizontalAlign {
+    field public static final androidx.constraintlayout.compose.HorizontalAlign.Companion Companion;
+  }
+
+  public static final class HorizontalAlign.Companion {
+    method public androidx.constraintlayout.compose.HorizontalAlign getCenter();
+    method public androidx.constraintlayout.compose.HorizontalAlign getEnd();
+    method public androidx.constraintlayout.compose.HorizontalAlign getStart();
+    property public final androidx.constraintlayout.compose.HorizontalAlign Center;
+    property public final androidx.constraintlayout.compose.HorizontalAlign End;
+    property public final androidx.constraintlayout.compose.HorizontalAlign Start;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface HorizontalAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.BaselineAnchor anchor, optional float margin, optional float goneMargin);
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Stable public final class HorizontalChainReference extends androidx.constraintlayout.compose.LayoutReference {
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getAbsoluteRight();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getEnd();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor getStart();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteLeft;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor absoluteRight;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor end;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor start;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class HorizontalChainScope {
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteLeft();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getAbsoluteRight();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getEnd();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public androidx.constraintlayout.compose.VerticalAnchorable getStart();
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteLeft;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable absoluteRight;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable end;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final androidx.constraintlayout.compose.VerticalAnchorable start;
+  }
+
+  public final class InvalidationStrategy {
+    ctor public InvalidationStrategy(optional kotlin.jvm.functions.Function3? onIncomingConstraints, kotlin.jvm.functions.Function0? onObservedStateChange);
+    method public kotlin.jvm.functions.Function3? getOnIncomingConstraints();
+    method public kotlin.jvm.functions.Function0? getOnObservedStateChange();
+    property public final kotlin.jvm.functions.Function3? onIncomingConstraints;
+    property public final kotlin.jvm.functions.Function0? onObservedStateChange;
+    field public static final androidx.constraintlayout.compose.InvalidationStrategy.Companion Companion;
+  }
+
+  public static final class InvalidationStrategy.Companion {
+    method public androidx.constraintlayout.compose.InvalidationStrategy getDefaultInvalidationStrategy();
+    property public final androidx.constraintlayout.compose.InvalidationStrategy DefaultInvalidationStrategy;
+  }
+
+  public final class InvalidationStrategySpecification {
+    method public boolean shouldInvalidateOnFixedHeight(long oldConstraints, long newConstraints, int skipCount, int threshold);
+    method public boolean shouldInvalidateOnFixedWidth(long oldConstraints, long newConstraints, int skipCount, int threshold);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyAttributeScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public float getAlpha();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public void setAlpha(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    property public final float alpha;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyAttributesScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyCycleScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public float getAlpha();
+    method public float getOffset();
+    method public float getPeriod();
+    method public float getPhase();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public void setAlpha(float);
+    method public void setOffset(float);
+    method public void setPeriod(float);
+    method public void setPhase(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    property public final float alpha;
+    property public final float offset;
+    property public final float period;
+    property public final float phase;
+    property public final float rotationX;
+    property public final float rotationY;
+    property public final float rotationZ;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final float translationX;
+    property public final float translationY;
+    property public final float translationZ;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyCyclesScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyPositionScope extends androidx.constraintlayout.compose.BaseKeyFrameScope {
+    method public androidx.constraintlayout.compose.CurveFit? getCurveFit();
+    method public float getPercentHeight();
+    method public float getPercentWidth();
+    method public float getPercentX();
+    method public float getPercentY();
+    method public void setCurveFit(androidx.constraintlayout.compose.CurveFit?);
+    method public void setPercentHeight(float);
+    method public void setPercentWidth(float);
+    method public void setPercentX(float);
+    method public void setPercentY(float);
+    property public final androidx.constraintlayout.compose.CurveFit? curveFit;
+    property public final float percentHeight;
+    property public final float percentWidth;
+    property public final float percentX;
+    property public final float percentY;
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class KeyPositionsScope extends androidx.constraintlayout.compose.BaseKeyFramesScope {
+    method public void frame(@IntRange(from=0L, to=100L) int frame, kotlin.jvm.functions.Function1 keyFrameContent);
+    method public androidx.constraintlayout.compose.RelativePosition getType();
+    method public void setType(androidx.constraintlayout.compose.RelativePosition);
+    property public final androidx.constraintlayout.compose.RelativePosition type;
+  }
+
+  public final class LateMotionLayoutKt {
+    method @androidx.compose.runtime.Composable @kotlin.PublishedApi internal static void LateMotionLayout(androidx.compose.runtime.MutableState start, androidx.compose.runtime.MutableState end, androidx.compose.animation.core.AnimationSpec animationSpec, kotlinx.coroutines.channels.Channel channel, androidx.compose.runtime.State contentTracker, androidx.compose.ui.node.Ref compositionSource, int optimizationLevel, kotlin.jvm.functions.Function0? finishedAnimationListener, androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0 content);
+  }
+
+  public enum LayoutInfoFlags {
+    enum_constant public static final androidx.constraintlayout.compose.LayoutInfoFlags BOUNDS;
+    enum_constant public static final androidx.constraintlayout.compose.LayoutInfoFlags NONE;
+  }
+
+  public interface LayoutInformationReceiver {
+    method public androidx.constraintlayout.compose.MotionLayoutDebugFlags getForcedDrawDebug();
+    method public int getForcedHeight();
+    method public float getForcedProgress();
+    method public int getForcedWidth();
+    method public androidx.constraintlayout.compose.LayoutInfoFlags getLayoutInformationMode();
+    method public void onNewProgress(float progress);
+    method public void resetForcedProgress();
+    method public void setLayoutInformation(String information);
+    method public void setUpdateFlag(androidx.compose.runtime.MutableState needsUpdate);
+  }
+
+  @androidx.compose.runtime.Stable public abstract class LayoutReference {
+  }
+
+  @kotlin.PublishedApi internal class Measurer implements androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer androidx.constraintlayout.compose.DesignInfoProvider {
+    ctor public Measurer(androidx.compose.ui.unit.Density density);
+    method public final void addLayoutInformationReceiver(androidx.constraintlayout.compose.LayoutInformationReceiver? layoutReceiver);
+    method protected final void applyRootSize(long constraints);
+    method public void computeLayoutResult();
+    method @androidx.compose.runtime.Composable public final void createDesignElements();
+    method public void didMeasures();
+    method @androidx.compose.runtime.Composable public final void drawDebugBounds(androidx.compose.foundation.layout.BoxScope, float forcedScaleFactor);
+    method public final void drawDebugBounds(androidx.compose.ui.graphics.drawscope.DrawScope, float forcedScaleFactor);
+    method public String getDesignInfo(int startX, int startY, String args);
+    method public final float getForcedScaleFactor();
+    method protected final java.util.Map getFrameCache();
+    method public final int getLayoutCurrentHeight();
+    method public final int getLayoutCurrentWidth();
+    method protected final androidx.constraintlayout.compose.LayoutInformationReceiver? getLayoutInformationReceiver();
+    method protected final java.util.Map getPlaceables();
+    method protected final androidx.constraintlayout.core.widgets.ConstraintWidgetContainer getRoot();
+    method protected final androidx.constraintlayout.compose.State getState();
+    method public void measure(androidx.constraintlayout.core.widgets.ConstraintWidget constraintWidget, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure measure);
+    method public final void parseDesignElements(androidx.constraintlayout.compose.ConstraintSet constraintSet);
+    method public final void performLayout(androidx.compose.ui.layout.Placeable.PlacementScope, java.util.List measurables);
+    method public final long performMeasure(long constraints, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.constraintlayout.compose.ConstraintSet constraintSet, java.util.List measurables, int optimizationLevel);
+    method public final void setForcedScaleFactor(float);
+    method protected final void setLayoutInformationReceiver(androidx.constraintlayout.compose.LayoutInformationReceiver?);
+    property public final float forcedScaleFactor;
+    property protected final java.util.Map frameCache;
+    property public final int layoutCurrentHeight;
+    property public final int layoutCurrentWidth;
+    property protected final androidx.constraintlayout.compose.LayoutInformationReceiver? layoutInformationReceiver;
+    property protected final java.util.Map placeables;
+    property protected final androidx.constraintlayout.core.widgets.ConstraintWidgetContainer root;
+    property protected final androidx.constraintlayout.compose.State state;
+  }
+
+  public final class MotionCarouselKt {
+    method @androidx.compose.runtime.Composable public static void ItemHolder(int i, String slotPrefix, boolean showSlot, kotlin.jvm.functions.Function0 function);
+    method @androidx.compose.runtime.Composable public static void MotionCarousel(androidx.constraintlayout.compose.MotionScene motionScene, int initialSlotIndex, int numSlots, optional String backwardTransition, optional String forwardTransition, optional String slotPrefix, optional boolean showSlots, kotlin.jvm.functions.Function1 content);
+    method public static inline  void items(androidx.constraintlayout.compose.MotionCarouselScope, java.util.List items, kotlin.jvm.functions.Function1 itemContent);
+    method public static inline  void itemsWithProperties(androidx.constraintlayout.compose.MotionCarouselScope, java.util.List items, kotlin.jvm.functions.Function2,kotlin.Unit> itemContent);
+  }
+
+  public interface MotionCarouselScope {
+    method public void items(int count, kotlin.jvm.functions.Function1 itemContent);
+    method public void itemsWithProperties(int count, kotlin.jvm.functions.Function2,kotlin.Unit> itemContent);
+  }
+
+  public interface MotionItemsProvider {
+    method public int count();
+    method public kotlin.jvm.functions.Function0 getContent(int index);
+    method public kotlin.jvm.functions.Function0 getContent(int index, androidx.compose.runtime.State properties);
+    method public boolean hasItemsWithProperties();
+  }
+
+  public enum MotionLayoutDebugFlags {
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags NONE;
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags SHOW_ALL;
+    enum_constant public static final androidx.constraintlayout.compose.MotionLayoutDebugFlags UNKNOWN;
+  }
+
+  @Deprecated public enum MotionLayoutFlag {
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag Default;
+    enum_constant @Deprecated public static final androidx.constraintlayout.compose.MotionLayoutFlag FullMeasure;
+  }
+
+  public final class MotionLayoutKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, float progress, optional androidx.compose.ui.Modifier modifier, optional androidx.constraintlayout.compose.Transition? transition, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, float progress, optional androidx.compose.ui.Modifier modifier, optional String transitionName, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static inline void MotionLayout(androidx.constraintlayout.compose.MotionScene motionScene, String? constraintSetName, androidx.compose.animation.core.AnimationSpec animationSpec, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0? finishedAnimationListener, optional int debugFlags, optional int optimizationLevel, optional androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi @kotlin.PublishedApi internal static void MotionLayoutCore(androidx.constraintlayout.compose.ConstraintSet start, androidx.constraintlayout.compose.ConstraintSet end, androidx.constraintlayout.compose.Transition? transition, float progress, androidx.constraintlayout.compose.LayoutInformationReceiver? informationReceiver, int optimizationLevel, boolean showBounds, boolean showPaths, boolean showKeyPositions, androidx.compose.ui.Modifier modifier, androidx.compose.runtime.MutableState contentTracker, androidx.compose.ui.node.Ref compositionSource, androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi @kotlin.PublishedApi internal static void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, float progress, String transitionName, int optimizationLevel, int debugFlags, androidx.compose.ui.Modifier modifier, androidx.compose.runtime.MutableState contentTracker, androidx.compose.ui.node.Ref compositionSource, androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi @kotlin.PublishedApi internal static void MotionLayoutCore(androidx.constraintlayout.compose.MotionScene motionScene, String? constraintSetName, androidx.compose.animation.core.AnimationSpec animationSpec, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0? finishedAnimationListener, optional int debugFlags, optional int optimizationLevel, androidx.compose.runtime.MutableState contentTracker, androidx.compose.ui.node.Ref compositionSource, androidx.constraintlayout.compose.InvalidationStrategy invalidationStrategy, kotlin.jvm.functions.Function1 content);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class MotionLayoutScope {
+    method public long customColor(String id, String name);
+    method public float customDistance(String id, String name);
+    method public float customFloat(String id, String name);
+    method public long customFontSize(String id, String name);
+    method public int customInt(String id, String name);
+    method public androidx.constraintlayout.compose.MotionLayoutScope.CustomProperties customProperties(String id);
+    method @Deprecated public long motionColor(String id, String name);
+    method @Deprecated public float motionDistance(String id, String name);
+    method @Deprecated public float motionFloat(String id, String name);
+    method @Deprecated public long motionFontSize(String id, String name);
+    method @Deprecated public int motionInt(String id, String name);
+    method @Deprecated @androidx.compose.runtime.Composable public androidx.compose.runtime.State motionProperties(String id);
+    method @Deprecated public androidx.constraintlayout.compose.MotionLayoutScope.MotionProperties motionProperties(String id, String tag);
+    method public androidx.compose.ui.Modifier onStartEndBoundsChanged(androidx.compose.ui.Modifier, Object layoutId, kotlin.jvm.functions.Function2 onBoundsChanged);
+  }
+
+  public final class MotionLayoutScope.CustomProperties {
+    method public long color(String name);
+    method public float distance(String name);
+    method public float float(String name);
+    method public long fontSize(String name);
+    method public int int(String name);
+  }
+
+  public final class MotionLayoutScope.MotionProperties {
+    method public long color(String name);
+    method public float distance(String name);
+    method public float float(String name);
+    method public long fontSize(String name);
+    method public String id();
+    method public int int(String name);
+    method public String? tag();
+  }
+
+  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.constraintlayout.compose.ExperimentalMotionApi public interface MotionScene extends androidx.constraintlayout.core.state.CoreMotionScene {
+    method public androidx.constraintlayout.compose.ConstraintSet? getConstraintSetInstance(String name);
+    method public androidx.constraintlayout.compose.Transition? getTransitionInstance(String name);
+  }
+
+  public final class MotionSceneKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.MotionScene MotionScene(@org.intellij.lang.annotations.Language("json5") String content);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class MotionSceneScope {
+    method public androidx.constraintlayout.compose.ConstraintSetRef addConstraintSet(androidx.constraintlayout.compose.ConstraintSet constraintSet, optional String? name);
+    method public void addTransition(androidx.constraintlayout.compose.Transition transition, optional String? name);
+    method public androidx.constraintlayout.compose.ConstraintSetRef constraintSet(optional String? name, optional androidx.constraintlayout.compose.ConstraintSetRef? extendConstraintSet, kotlin.jvm.functions.Function1 constraintSetContent);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public androidx.constraintlayout.compose.MotionSceneScope.ConstrainedLayoutReferences createRefsFor(java.lang.Object... ids);
+    method public void customColor(androidx.constraintlayout.compose.ConstrainScope, String name, long value);
+    method public void customColor(androidx.constraintlayout.compose.KeyAttributeScope, String name, long value);
+    method public void customDistance(androidx.constraintlayout.compose.ConstrainScope, String name, float value);
+    method public void customDistance(androidx.constraintlayout.compose.KeyAttributeScope, String name, float value);
+    method public void customFloat(androidx.constraintlayout.compose.ConstrainScope, String name, float value);
+    method public void customFloat(androidx.constraintlayout.compose.KeyAttributeScope, String name, float value);
+    method public void customFontSize(androidx.constraintlayout.compose.ConstrainScope, String name, long value);
+    method public void customFontSize(androidx.constraintlayout.compose.KeyAttributeScope, String name, long value);
+    method public void customInt(androidx.constraintlayout.compose.ConstrainScope, String name, int value);
+    method public void customInt(androidx.constraintlayout.compose.KeyAttributeScope, String name, int value);
+    method public void defaultTransition(androidx.constraintlayout.compose.ConstraintSetRef from, androidx.constraintlayout.compose.ConstraintSetRef to, optional kotlin.jvm.functions.Function1 transitionContent);
+    method public float getStaggeredWeight(androidx.constraintlayout.compose.ConstrainScope);
+    method public void setStaggeredWeight(androidx.constraintlayout.compose.ConstrainScope, float);
+    method public void transition(androidx.constraintlayout.compose.ConstraintSetRef from, androidx.constraintlayout.compose.ConstraintSetRef to, optional String? name, kotlin.jvm.functions.Function1 transitionContent);
+  }
+
+  public final class MotionSceneScope.ConstrainedLayoutReferences {
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component1();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component10();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component11();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component12();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component13();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component14();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component15();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component16();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component2();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component3();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component4();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component5();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component6();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component7();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component8();
+    method public operator androidx.constraintlayout.compose.ConstrainedLayoutReference component9();
+  }
+
+  public final class MotionSceneScopeKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.MotionScene MotionScene(kotlin.jvm.functions.Function1 motionSceneContent);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class OnSwipe {
+    ctor public OnSwipe(androidx.constraintlayout.compose.ConstrainedLayoutReference anchor, androidx.constraintlayout.compose.SwipeSide side, androidx.constraintlayout.compose.SwipeDirection direction, optional float dragScale, optional float dragThreshold, optional androidx.constraintlayout.compose.ConstrainedLayoutReference? dragAround, optional androidx.constraintlayout.compose.ConstrainedLayoutReference? limitBoundsTo, optional androidx.constraintlayout.compose.SwipeTouchUp onTouchUp, optional androidx.constraintlayout.compose.SwipeMode mode);
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getAnchor();
+    method public androidx.constraintlayout.compose.SwipeDirection getDirection();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference? getDragAround();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference? getLimitBoundsTo();
+    method public androidx.constraintlayout.compose.SwipeMode getMode();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getOnTouchUp();
+    method public androidx.constraintlayout.compose.SwipeSide getSide();
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference anchor;
+    property public final androidx.constraintlayout.compose.SwipeDirection direction;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference? dragAround;
+    property public final float dragScale;
+    property public final float dragThreshold;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference? limitBoundsTo;
+    property public final androidx.constraintlayout.compose.SwipeMode mode;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp onTouchUp;
+    property public final androidx.constraintlayout.compose.SwipeSide side;
+  }
+
+  @androidx.compose.runtime.Immutable @kotlin.PublishedApi internal final class RawConstraintSet implements androidx.constraintlayout.compose.ConstraintSet {
+    ctor public RawConstraintSet(androidx.constraintlayout.core.parser.CLObject clObject);
+    method public void applyTo(androidx.constraintlayout.compose.State state, java.util.List measurables);
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class RelativePosition {
+    method public String getName();
+    property public String name;
+    field public static final androidx.constraintlayout.compose.RelativePosition.Companion Companion;
+  }
+
+  public static final class RelativePosition.Companion {
+    method public androidx.constraintlayout.compose.RelativePosition getDelta();
+    method public androidx.constraintlayout.compose.RelativePosition getParent();
+    method public androidx.constraintlayout.compose.RelativePosition getPath();
+    property public final androidx.constraintlayout.compose.RelativePosition Delta;
+    property public final androidx.constraintlayout.compose.RelativePosition Parent;
+    property public final androidx.constraintlayout.compose.RelativePosition Path;
+  }
+
+  @kotlin.jvm.JvmInline public final value class Skip {
+    ctor public Skip(@IntRange(from=0L) int position, @IntRange(from=1L) int size);
+    ctor public Skip(@IntRange(from=0L) int position, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns);
+    method public String getDescription();
+    property public final String description;
+  }
+
+  @kotlin.jvm.JvmInline public final value class Span {
+    ctor public Span(@IntRange(from=0L) int position, @IntRange(from=1L) int size);
+    ctor public Span(@IntRange(from=0L) int position, @IntRange(from=1L) int rows, @IntRange(from=1L) int columns);
+    ctor public Span(String description);
+    method public String getDescription();
+    property public final String description;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SpringBoundary {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SpringBoundary.Companion Companion;
+  }
+
+  public static final class SpringBoundary.Companion {
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceBoth();
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceEnd();
+    method public androidx.constraintlayout.compose.SpringBoundary getBounceStart();
+    method public androidx.constraintlayout.compose.SpringBoundary getOvershoot();
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceBoth;
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceEnd;
+    property public final androidx.constraintlayout.compose.SpringBoundary BounceStart;
+    property public final androidx.constraintlayout.compose.SpringBoundary Overshoot;
+  }
+
+  public final class State extends androidx.constraintlayout.core.state.State {
+    ctor public State(androidx.compose.ui.unit.Density density);
+    method public androidx.compose.ui.unit.Density getDensity();
+    method @Deprecated public androidx.compose.ui.unit.LayoutDirection getLayoutDirection();
+    method public long getRootIncomingConstraints();
+    method @Deprecated public void setLayoutDirection(androidx.compose.ui.unit.LayoutDirection);
+    method public void setRootIncomingConstraints(long);
+    property public final androidx.compose.ui.unit.Density density;
+    property @Deprecated public final androidx.compose.ui.unit.LayoutDirection layoutDirection;
+    property public final long rootIncomingConstraints;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeDirection {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeDirection.Companion Companion;
+  }
+
+  public static final class SwipeDirection.Companion {
+    method public androidx.constraintlayout.compose.SwipeDirection getClockwise();
+    method public androidx.constraintlayout.compose.SwipeDirection getCounterclockwise();
+    method public androidx.constraintlayout.compose.SwipeDirection getDown();
+    method public androidx.constraintlayout.compose.SwipeDirection getEnd();
+    method public androidx.constraintlayout.compose.SwipeDirection getLeft();
+    method public androidx.constraintlayout.compose.SwipeDirection getRight();
+    method public androidx.constraintlayout.compose.SwipeDirection getStart();
+    method public androidx.constraintlayout.compose.SwipeDirection getUp();
+    property public final androidx.constraintlayout.compose.SwipeDirection Clockwise;
+    property public final androidx.constraintlayout.compose.SwipeDirection Counterclockwise;
+    property public final androidx.constraintlayout.compose.SwipeDirection Down;
+    property public final androidx.constraintlayout.compose.SwipeDirection End;
+    property public final androidx.constraintlayout.compose.SwipeDirection Left;
+    property public final androidx.constraintlayout.compose.SwipeDirection Right;
+    property public final androidx.constraintlayout.compose.SwipeDirection Start;
+    property public final androidx.constraintlayout.compose.SwipeDirection Up;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeMode {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeMode.Companion Companion;
+  }
+
+  public static final class SwipeMode.Companion {
+    method public androidx.constraintlayout.compose.SwipeMode getSpring();
+    method public androidx.constraintlayout.compose.SwipeMode getVelocity();
+    method public androidx.constraintlayout.compose.SwipeMode spring(optional float mass, optional float stiffness, optional float damping, optional float threshold, optional androidx.constraintlayout.compose.SpringBoundary boundary);
+    method public androidx.constraintlayout.compose.SwipeMode velocity(optional float maxVelocity, optional float maxAcceleration);
+    property public final androidx.constraintlayout.compose.SwipeMode Spring;
+    property public final androidx.constraintlayout.compose.SwipeMode Velocity;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeSide {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeSide.Companion Companion;
+  }
+
+  public static final class SwipeSide.Companion {
+    method public androidx.constraintlayout.compose.SwipeSide getBottom();
+    method public androidx.constraintlayout.compose.SwipeSide getEnd();
+    method public androidx.constraintlayout.compose.SwipeSide getLeft();
+    method public androidx.constraintlayout.compose.SwipeSide getMiddle();
+    method public androidx.constraintlayout.compose.SwipeSide getRight();
+    method public androidx.constraintlayout.compose.SwipeSide getStart();
+    method public androidx.constraintlayout.compose.SwipeSide getTop();
+    property public final androidx.constraintlayout.compose.SwipeSide Bottom;
+    property public final androidx.constraintlayout.compose.SwipeSide End;
+    property public final androidx.constraintlayout.compose.SwipeSide Left;
+    property public final androidx.constraintlayout.compose.SwipeSide Middle;
+    property public final androidx.constraintlayout.compose.SwipeSide Right;
+    property public final androidx.constraintlayout.compose.SwipeSide Start;
+    property public final androidx.constraintlayout.compose.SwipeSide Top;
+  }
+
+  @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public final class SwipeTouchUp {
+    method public String getName();
+    property public final String name;
+    field public static final androidx.constraintlayout.compose.SwipeTouchUp.Companion Companion;
+  }
+
+  public static final class SwipeTouchUp.Companion {
+    method public androidx.constraintlayout.compose.SwipeTouchUp getAutoComplete();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getDecelerate();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getNeverCompleteEnd();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getNeverCompleteStart();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getStop();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getToEnd();
+    method public androidx.constraintlayout.compose.SwipeTouchUp getToStart();
+    property public final androidx.constraintlayout.compose.SwipeTouchUp AutoComplete;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp Decelerate;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp NeverCompleteEnd;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp NeverCompleteStart;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp Stop;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp ToEnd;
+    property public final androidx.constraintlayout.compose.SwipeTouchUp ToStart;
+  }
+
+  public final class ToolingUtilsKt {
+    method public static androidx.compose.ui.semantics.SemanticsPropertyKey getDesignInfoDataKey();
+    property public static final androidx.compose.ui.semantics.SemanticsPropertyKey DesignInfoDataKey;
+    field @kotlin.PublishedApi internal static final androidx.compose.ui.semantics.SemanticsPropertyKey designInfoProvider$delegate;
+  }
+
+  @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.constraintlayout.compose.ExperimentalMotionApi public interface Transition {
+    method public String getEndConstraintSetId();
+    method public String getStartConstraintSetId();
+  }
+
+  public final class TransitionKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.Transition Transition(@org.intellij.lang.annotations.Language("json5") String content);
+  }
+
+  @SuppressCompatibility @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.constraintlayout.compose.ExperimentalMotionApi public final class TransitionScope {
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference createRefFor(Object id);
+    method public float getMaxStaggerDelay();
+    method public androidx.constraintlayout.compose.Arc getMotionArc();
+    method public androidx.constraintlayout.compose.OnSwipe? getOnSwipe();
+    method public void keyAttributes(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyAttributesContent);
+    method public void keyCycles(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyCyclesContent);
+    method public void keyPositions(androidx.constraintlayout.compose.ConstrainedLayoutReference[] targets, kotlin.jvm.functions.Function1 keyPositionsContent);
+    method public void setMaxStaggerDelay(float);
+    method public void setMotionArc(androidx.constraintlayout.compose.Arc);
+    method public void setOnSwipe(androidx.constraintlayout.compose.OnSwipe?);
+    property public final float maxStaggerDelay;
+    property public final androidx.constraintlayout.compose.Arc motionArc;
+    property public final androidx.constraintlayout.compose.OnSwipe? onSwipe;
+  }
+
+  public final class TransitionScopeKt {
+    method @SuppressCompatibility @androidx.constraintlayout.compose.ExperimentalMotionApi public static androidx.constraintlayout.compose.Transition Transition(optional String from, optional String to, kotlin.jvm.functions.Function1 content);
+  }
+
+  @androidx.compose.runtime.Immutable public final class VerticalAlign {
+    field public static final androidx.constraintlayout.compose.VerticalAlign.Companion Companion;
+  }
+
+  public static final class VerticalAlign.Companion {
+    method public androidx.constraintlayout.compose.VerticalAlign getBaseline();
+    method public androidx.constraintlayout.compose.VerticalAlign getBottom();
+    method public androidx.constraintlayout.compose.VerticalAlign getCenter();
+    method public androidx.constraintlayout.compose.VerticalAlign getTop();
+    property public final androidx.constraintlayout.compose.VerticalAlign Baseline;
+    property public final androidx.constraintlayout.compose.VerticalAlign Bottom;
+    property public final androidx.constraintlayout.compose.VerticalAlign Center;
+    property public final androidx.constraintlayout.compose.VerticalAlign Top;
+  }
+
+  @kotlin.jvm.JvmDefaultWithCompatibility public interface VerticalAnchorable {
+    method public void linkTo(androidx.constraintlayout.compose.ConstraintLayoutBaseScope.VerticalAnchor anchor, optional float margin, optional float goneMargin);
+  }
+
+  @androidx.compose.runtime.Stable public final class VerticalChainReference extends androidx.constraintlayout.compose.LayoutReference {
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getBottom();
+    method public androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor getTop();
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor bottom;
+    property public final androidx.constraintlayout.compose.ConstraintLayoutBaseScope.HorizontalAnchor top;
+  }
+
+  @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Stable public final class VerticalChainScope {
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getBottom();
+    method public androidx.constraintlayout.compose.ConstrainedLayoutReference getParent();
+    method public androidx.constraintlayout.compose.HorizontalAnchorable getTop();
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable bottom;
+    property public final androidx.constraintlayout.compose.ConstrainedLayoutReference parent;
+    property public final androidx.constraintlayout.compose.HorizontalAnchorable top;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Visibility {
+    field public static final androidx.constraintlayout.compose.Visibility.Companion Companion;
+  }
+
+  public static final class Visibility.Companion {
+    method public androidx.constraintlayout.compose.Visibility getGone();
+    method public androidx.constraintlayout.compose.Visibility getInvisible();
+    method public androidx.constraintlayout.compose.Visibility getVisible();
+    property public final androidx.constraintlayout.compose.Visibility Gone;
+    property public final androidx.constraintlayout.compose.Visibility Invisible;
+    property public final androidx.constraintlayout.compose.Visibility Visible;
+  }
+
+  @androidx.compose.runtime.Immutable public final class Wrap {
+    field public static final androidx.constraintlayout.compose.Wrap.Companion Companion;
+  }
+
+  public static final class Wrap.Companion {
+    method public androidx.constraintlayout.compose.Wrap getAligned();
+    method public androidx.constraintlayout.compose.Wrap getChain();
+    method public androidx.constraintlayout.compose.Wrap getNone();
+    property public final androidx.constraintlayout.compose.Wrap Aligned;
+    property public final androidx.constraintlayout.compose.Wrap Chain;
+    property public final androidx.constraintlayout.compose.Wrap None;
+  }
+
+}
+
diff --git a/constraintlayout/constraintlayout-core/api/1.1.0-beta01.txt b/constraintlayout/constraintlayout-core/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..5be1d12
--- /dev/null
+++ b/constraintlayout/constraintlayout-core/api/1.1.0-beta01.txt
@@ -0,0 +1,3393 @@
+// Signature format: 4.0
+package androidx.constraintlayout.core {
+
+  public class ArrayLinkedVariables implements androidx.constraintlayout.core.ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public final void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public final float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public int getHead();
+    method public final int getId(int);
+    method public final int getNextIndice(int);
+    method public final float getValue(int);
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public final void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public final float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+    field protected final androidx.constraintlayout.core.Cache! mCache;
+  }
+
+  public class ArrayRow {
+    ctor public ArrayRow();
+    ctor public ArrayRow(androidx.constraintlayout.core.Cache!);
+    method public androidx.constraintlayout.core.ArrayRow! addError(androidx.constraintlayout.core.LinearSystem!, int);
+    method public void addError(androidx.constraintlayout.core.SolverVariable!);
+    method public void clear();
+    method public androidx.constraintlayout.core.ArrayRow! createRowDimensionRatio(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEqualDimension(float, float, float, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEqualMatchDimensions(float, float, float, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEquals(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEquals(androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowGreaterThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowGreaterThan(androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!);
+    method public androidx.constraintlayout.core.ArrayRow! createRowLowerThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowWithAngle(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.SolverVariable! getKey();
+    method public androidx.constraintlayout.core.SolverVariable! getPivotCandidate(androidx.constraintlayout.core.LinearSystem!, boolean[]!);
+    method public void initFromRow(androidx.constraintlayout.core.LinearSystem.Row!);
+    method public boolean isEmpty();
+    method public androidx.constraintlayout.core.SolverVariable! pickPivot(androidx.constraintlayout.core.SolverVariable!);
+    method public void reset();
+    method public void updateFromFinalVariable(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public void updateFromRow(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.ArrayRow!, boolean);
+    method public void updateFromSynonymVariable(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public void updateFromSystem(androidx.constraintlayout.core.LinearSystem!);
+    field public androidx.constraintlayout.core.ArrayRow.ArrayRowVariables! variables;
+  }
+
+  public static interface ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+  }
+
+  public class Cache {
+    ctor public Cache();
+  }
+
+  public class GoalRow extends androidx.constraintlayout.core.ArrayRow {
+    ctor public GoalRow(androidx.constraintlayout.core.Cache!);
+  }
+
+  public class LinearSystem {
+    ctor public LinearSystem();
+    method public void addCenterPoint(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintWidget!, float, int);
+    method public void addCentering(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, float, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addConstraint(androidx.constraintlayout.core.ArrayRow!);
+    method public androidx.constraintlayout.core.ArrayRow! addEquality(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addEquality(androidx.constraintlayout.core.SolverVariable!, int);
+    method public void addGreaterBarrier(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, boolean);
+    method public void addGreaterThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addLowerBarrier(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, boolean);
+    method public void addLowerThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addRatio(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float, int);
+    method public void addSynonym(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.SolverVariable! createErrorVariable(int, String!);
+    method public androidx.constraintlayout.core.SolverVariable! createExtraVariable();
+    method public androidx.constraintlayout.core.SolverVariable! createObjectVariable(Object!);
+    method public androidx.constraintlayout.core.ArrayRow! createRow();
+    method public static androidx.constraintlayout.core.ArrayRow! createRowDimensionPercent(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.SolverVariable! createSlackVariable();
+    method public void displayReadableRows();
+    method public void displayVariablesReadableRows();
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method public androidx.constraintlayout.core.Cache! getCache();
+    method public int getMemoryUsed();
+    method public static androidx.constraintlayout.core.Metrics! getMetrics();
+    method public int getNumEquations();
+    method public int getNumVariables();
+    method public int getObjectVariableValue(Object!);
+    method public void minimize() throws java.lang.Exception;
+    method public void removeRow(androidx.constraintlayout.core.ArrayRow!);
+    method public void reset();
+    field public static long ARRAY_ROW_CREATION;
+    field public static final boolean DEBUG = false;
+    field public static final boolean FULL_DEBUG = false;
+    field public static long OPTIMIZED_ARRAY_ROW_CREATION;
+    field public static boolean OPTIMIZED_ENGINE;
+    field public static boolean SIMPLIFY_SYNONYMS;
+    field public static boolean SKIP_COLUMNS;
+    field public static boolean USE_BASIC_SYNONYMS;
+    field public static boolean USE_DEPENDENCY_ORDERING;
+    field public static boolean USE_SYNONYMS;
+    field public boolean graphOptimizer;
+    field public boolean hasSimpleDefinition;
+    field public boolean newgraphOptimizer;
+    field public static androidx.constraintlayout.core.Metrics! sMetrics;
+  }
+
+  public class Metrics {
+    ctor public Metrics();
+    method public void copy(androidx.constraintlayout.core.Metrics!);
+    method public void reset();
+    field public long additionalMeasures;
+    field public long bfs;
+    field public long constraints;
+    field public long determineGroups;
+    field public long errors;
+    field public long extravariables;
+    field public long fullySolved;
+    field public long graphOptimizer;
+    field public long graphSolved;
+    field public long grouping;
+    field public long infeasibleDetermineGroups;
+    field public long iterations;
+    field public long lastTableSize;
+    field public long layouts;
+    field public long linearSolved;
+    field public long mChildCount;
+    field public long mEquations;
+    field public long mMeasureCalls;
+    field public long mMeasureDuration;
+    field public int mNumberOfLayouts;
+    field public int mNumberOfMeasures;
+    field public long mSimpleEquations;
+    field public long mSolverPasses;
+    field public long mVariables;
+    field public long maxRows;
+    field public long maxTableSize;
+    field public long maxVariables;
+    field public long measuredMatchWidgets;
+    field public long measuredWidgets;
+    field public long measures;
+    field public long measuresLayoutDuration;
+    field public long measuresWidgetsDuration;
+    field public long measuresWrap;
+    field public long measuresWrapInfeasible;
+    field public long minimize;
+    field public long minimizeGoal;
+    field public long nonresolvedWidgets;
+    field public long optimize;
+    field public long pivots;
+    field public java.util.ArrayList! problematicLayouts;
+    field public long resolutions;
+    field public long resolvedWidgets;
+    field public long simpleconstraints;
+    field public long slackvariables;
+    field public long tableSizeIncrease;
+    field public long variables;
+    field public long widgets;
+  }
+
+  public class PriorityGoalRow extends androidx.constraintlayout.core.ArrayRow {
+    ctor public PriorityGoalRow(androidx.constraintlayout.core.Cache!);
+  }
+
+  public class SolverVariable implements java.lang.Comparable {
+    ctor public SolverVariable(androidx.constraintlayout.core.SolverVariable.Type!, String!);
+    ctor public SolverVariable(String!, androidx.constraintlayout.core.SolverVariable.Type!);
+    method public final void addToRow(androidx.constraintlayout.core.ArrayRow!);
+    method public int compareTo(androidx.constraintlayout.core.SolverVariable!);
+    method public String! getName();
+    method public final void removeFromRow(androidx.constraintlayout.core.ArrayRow!);
+    method public void reset();
+    method public void setFinalValue(androidx.constraintlayout.core.LinearSystem!, float);
+    method public void setName(String!);
+    method public void setSynonym(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public void setType(androidx.constraintlayout.core.SolverVariable.Type!, String!);
+    method public final void updateReferencesWithNewDefinition(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.ArrayRow!);
+    field public static final int STRENGTH_BARRIER = 6; // 0x6
+    field public static final int STRENGTH_CENTERING = 7; // 0x7
+    field public static final int STRENGTH_EQUALITY = 5; // 0x5
+    field public static final int STRENGTH_FIXED = 8; // 0x8
+    field public static final int STRENGTH_HIGH = 3; // 0x3
+    field public static final int STRENGTH_HIGHEST = 4; // 0x4
+    field public static final int STRENGTH_LOW = 1; // 0x1
+    field public static final int STRENGTH_MEDIUM = 2; // 0x2
+    field public static final int STRENGTH_NONE = 0; // 0x0
+    field public float computedValue;
+    field public int id;
+    field public boolean inGoal;
+    field public boolean isFinalValue;
+    field public int strength;
+    field public int usageInRowCount;
+  }
+
+  public enum SolverVariable.Type {
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type CONSTANT;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type ERROR;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type SLACK;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type UNKNOWN;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type UNRESTRICTED;
+  }
+
+  public class SolverVariableValues implements androidx.constraintlayout.core.ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+    field protected final androidx.constraintlayout.core.Cache! mCache;
+  }
+
+}
+
+package androidx.constraintlayout.core.dsl {
+
+  public class Barrier extends androidx.constraintlayout.core.dsl.Helper {
+    ctor public Barrier(String!);
+    ctor public Barrier(String!, String!);
+    method public androidx.constraintlayout.core.dsl.Barrier! addReference(androidx.constraintlayout.core.dsl.Ref!);
+    method public androidx.constraintlayout.core.dsl.Barrier! addReference(String!);
+    method public androidx.constraintlayout.core.dsl.Constraint.Side! getDirection();
+    method public int getMargin();
+    method public String! referencesToString();
+    method public void setDirection(androidx.constraintlayout.core.dsl.Constraint.Side!);
+    method public void setMargin(int);
+  }
+
+  public abstract class Chain extends androidx.constraintlayout.core.dsl.Helper {
+    ctor public Chain(String!);
+    method public androidx.constraintlayout.core.dsl.Chain! addReference(androidx.constraintlayout.core.dsl.Ref!);
+    method public androidx.constraintlayout.core.dsl.Chain! addReference(String!);
+    method public androidx.constraintlayout.core.dsl.Chain.Style! getStyle();
+    method public String! referencesToString();
+    method public void setStyle(androidx.constraintlayout.core.dsl.Chain.Style!);
+    field protected java.util.ArrayList! references;
+    field protected static final java.util.Map! styleMap;
+  }
+
+  public class Chain.Anchor {
+    method public void build(StringBuilder!);
+    method public String! getId();
+  }
+
+  public enum Chain.Style {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style PACKED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style SPREAD_INSIDE;
+  }
+
+  public class Constraint {
+    ctor public Constraint(String!);
+    method protected void append(StringBuilder!, String!, float);
+    method public String! convertStringArrayToString(String![]!);
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getBaseline();
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getBottom();
+    method public float getCircleAngle();
+    method public String! getCircleConstraint();
+    method public int getCircleRadius();
+    method public String! getDimensionRatio();
+    method public int getEditorAbsoluteX();
+    method public int getEditorAbsoluteY();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getEnd();
+    method public int getHeight();
+    method public androidx.constraintlayout.core.dsl.Constraint.Behaviour! getHeightDefault();
+    method public int getHeightMax();
+    method public int getHeightMin();
+    method public float getHeightPercent();
+    method public float getHorizontalBias();
+    method public androidx.constraintlayout.core.dsl.Constraint.ChainMode! getHorizontalChainStyle();
+    method public float getHorizontalWeight();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getLeft();
+    method public String![]! getReferenceIds();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getRight();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getStart();
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getTop();
+    method public float getVerticalBias();
+    method public androidx.constraintlayout.core.dsl.Constraint.ChainMode! getVerticalChainStyle();
+    method public float getVerticalWeight();
+    method public int getWidth();
+    method public androidx.constraintlayout.core.dsl.Constraint.Behaviour! getWidthDefault();
+    method public int getWidthMax();
+    method public int getWidthMin();
+    method public float getWidthPercent();
+    method public boolean isConstrainedHeight();
+    method public boolean isConstrainedWidth();
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void setCircleAngle(float);
+    method public void setCircleConstraint(String!);
+    method public void setCircleRadius(int);
+    method public void setConstrainedHeight(boolean);
+    method public void setConstrainedWidth(boolean);
+    method public void setDimensionRatio(String!);
+    method public void setEditorAbsoluteX(int);
+    method public void setEditorAbsoluteY(int);
+    method public void setHeight(int);
+    method public void setHeightDefault(androidx.constraintlayout.core.dsl.Constraint.Behaviour!);
+    method public void setHeightMax(int);
+    method public void setHeightMin(int);
+    method public void setHeightPercent(float);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalChainStyle(androidx.constraintlayout.core.dsl.Constraint.ChainMode!);
+    method public void setHorizontalWeight(float);
+    method public void setReferenceIds(String![]!);
+    method public void setVerticalBias(float);
+    method public void setVerticalChainStyle(androidx.constraintlayout.core.dsl.Constraint.ChainMode!);
+    method public void setVerticalWeight(float);
+    method public void setWidth(int);
+    method public void setWidthDefault(androidx.constraintlayout.core.dsl.Constraint.Behaviour!);
+    method public void setWidthMax(int);
+    method public void setWidthMin(int);
+    method public void setWidthPercent(float);
+    field public static final androidx.constraintlayout.core.dsl.Constraint! PARENT;
+  }
+
+  public class Constraint.Anchor {
+    method public void build(StringBuilder!);
+    method public String! getId();
+  }
+
+  public enum Constraint.Behaviour {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour PERCENT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour RATIO;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour RESOLVED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour WRAP;
+  }
+
+  public enum Constraint.ChainMode {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode PACKED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode SPREAD_INSIDE;
+  }
+
+  public class Constraint.HAnchor extends androidx.constraintlayout.core.dsl.Constraint.Anchor {
+  }
+
+  public enum Constraint.HSide {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide START;
+  }
+
+  public enum Constraint.Side {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side TOP;
+  }
+
+  public class Constraint.VAnchor extends androidx.constraintlayout.core.dsl.Constraint.Anchor {
+  }
+
+  public enum Constraint.VSide {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide TOP;
+  }
+
+  public class ConstraintSet {
+    ctor public ConstraintSet(String!);
+    method public void add(androidx.constraintlayout.core.dsl.Constraint!);
+    method public void add(androidx.constraintlayout.core.dsl.Helper!);
+  }
+
+  public abstract class Guideline extends androidx.constraintlayout.core.dsl.Helper {
+    method public int getEnd();
+    method public float getPercent();
+    method public int getStart();
+    method public void setEnd(int);
+    method public void setPercent(float);
+    method public void setStart(int);
+  }
+
+  public class HChain extends androidx.constraintlayout.core.dsl.Chain {
+    ctor public HChain(String!);
+    ctor public HChain(String!, String!);
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getEnd();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getLeft();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getRight();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getStart();
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+  }
+
+  public class HChain.HAnchor extends androidx.constraintlayout.core.dsl.Chain.Anchor {
+  }
+
+  public class Helper {
+    ctor public Helper(String!, androidx.constraintlayout.core.dsl.Helper.HelperType!);
+    ctor public Helper(String!, androidx.constraintlayout.core.dsl.Helper.HelperType!, String!);
+    method public void append(java.util.Map!, StringBuilder!);
+    method public java.util.Map! convertConfigToMap();
+    method public String! getConfig();
+    method public String! getId();
+    method public androidx.constraintlayout.core.dsl.Helper.HelperType! getType();
+    method public static void main(String![]!);
+    field protected String! config;
+    field protected java.util.Map! configMap;
+    field protected final String! name;
+    field protected static final java.util.Map! sideMap;
+    field protected androidx.constraintlayout.core.dsl.Helper.HelperType! type;
+    field protected static final java.util.Map! typeMap;
+  }
+
+  public static final class Helper.HelperType {
+    ctor public Helper.HelperType(String!);
+  }
+
+  public enum Helper.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type BARRIER;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type HORIZONTAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type HORIZONTAL_GUIDELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type VERTICAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type VERTICAL_GUIDELINE;
+  }
+
+  public class KeyAttribute extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyAttribute(int, String!);
+    method protected void attributesToString(StringBuilder!);
+    method public float getAlpha();
+    method public androidx.constraintlayout.core.dsl.KeyAttribute.Fit! getCurveFit();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public String! getTarget();
+    method public String! getTransitionEasing();
+    method public float getTransitionPathRotate();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public androidx.constraintlayout.core.dsl.KeyAttribute.Visibility! getVisibility();
+    method public void setAlpha(float);
+    method public void setCurveFit(androidx.constraintlayout.core.dsl.KeyAttribute.Fit!);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotation(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTarget(String!);
+    method public void setTransitionEasing(String!);
+    method public void setTransitionPathRotate(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public void setVisibility(androidx.constraintlayout.core.dsl.KeyAttribute.Visibility!);
+    field protected String! TYPE;
+  }
+
+  public enum KeyAttribute.Fit {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Fit LINEAR;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Fit SPLINE;
+  }
+
+  public enum KeyAttribute.Visibility {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility GONE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility INVISIBLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility VISIBLE;
+  }
+
+  public class KeyAttributes extends androidx.constraintlayout.core.dsl.Keys {
+    method protected void attributesToString(StringBuilder!);
+    method public float[]! getAlpha();
+    method public androidx.constraintlayout.core.dsl.KeyAttributes.Fit! getCurveFit();
+    method public float[]! getPivotX();
+    method public float[]! getPivotY();
+    method public float[]! getRotation();
+    method public float[]! getRotationX();
+    method public float[]! getRotationY();
+    method public float[]! getScaleX();
+    method public float[]! getScaleY();
+    method public String![]! getTarget();
+    method public String! getTransitionEasing();
+    method public float[]! getTransitionPathRotate();
+    method public float[]! getTranslationX();
+    method public float[]! getTranslationY();
+    method public float[]! getTranslationZ();
+    method public androidx.constraintlayout.core.dsl.KeyAttributes.Visibility![]! getVisibility();
+    method public void setAlpha(float...!);
+    method public void setCurveFit(androidx.constraintlayout.core.dsl.KeyAttributes.Fit!);
+    method public void setPivotX(float...!);
+    method public void setPivotY(float...!);
+    method public void setRotation(float...!);
+    method public void setRotationX(float...!);
+    method public void setRotationY(float...!);
+    method public void setScaleX(float[]!);
+    method public void setScaleY(float[]!);
+    method public void setTarget(String![]!);
+    method public void setTransitionEasing(String!);
+    method public void setTransitionPathRotate(float...!);
+    method public void setTranslationX(float[]!);
+    method public void setTranslationY(float[]!);
+    method public void setTranslationZ(float[]!);
+    method public void setVisibility(androidx.constraintlayout.core.dsl.KeyAttributes.Visibility!...!);
+    field protected String! TYPE;
+  }
+
+  public enum KeyAttributes.Fit {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Fit LINEAR;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Fit SPLINE;
+  }
+
+  public enum KeyAttributes.Visibility {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility GONE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility INVISIBLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility VISIBLE;
+  }
+
+  public class KeyCycle extends androidx.constraintlayout.core.dsl.KeyAttribute {
+    method public float getOffset();
+    method public float getPeriod();
+    method public float getPhase();
+    method public androidx.constraintlayout.core.dsl.KeyCycle.Wave! getShape();
+    method public void setOffset(float);
+    method public void setPeriod(float);
+    method public void setPhase(float);
+    method public void setShape(androidx.constraintlayout.core.dsl.KeyCycle.Wave!);
+  }
+
+  public enum KeyCycle.Wave {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave COS;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave REVERSE_SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SQUARE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave TRIANGLE;
+  }
+
+  public class KeyCycles extends androidx.constraintlayout.core.dsl.KeyAttributes {
+    method public float[]! getWaveOffset();
+    method public float[]! getWavePeriod();
+    method public float[]! getWavePhase();
+    method public androidx.constraintlayout.core.dsl.KeyCycles.Wave! getWaveShape();
+    method public void setWaveOffset(float...!);
+    method public void setWavePeriod(float...!);
+    method public void setWavePhase(float...!);
+    method public void setWaveShape(androidx.constraintlayout.core.dsl.KeyCycles.Wave!);
+  }
+
+  public enum KeyCycles.Wave {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave COS;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave REVERSE_SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SQUARE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave TRIANGLE;
+  }
+
+  public class KeyFrames {
+    ctor public KeyFrames();
+    method public void add(androidx.constraintlayout.core.dsl.Keys!);
+  }
+
+  public class KeyPosition extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyPosition(String!, int);
+    method public int getFrames();
+    method public float getPercentHeight();
+    method public float getPercentWidth();
+    method public float getPercentX();
+    method public float getPercentY();
+    method public androidx.constraintlayout.core.dsl.KeyPosition.Type! getPositionType();
+    method public String! getTarget();
+    method public String! getTransitionEasing();
+    method public void setFrames(int);
+    method public void setPercentHeight(float);
+    method public void setPercentWidth(float);
+    method public void setPercentX(float);
+    method public void setPercentY(float);
+    method public void setPositionType(androidx.constraintlayout.core.dsl.KeyPosition.Type!);
+    method public void setTarget(String!);
+    method public void setTransitionEasing(String!);
+  }
+
+  public enum KeyPosition.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type CARTESIAN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type PATH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type SCREEN;
+  }
+
+  public class KeyPositions extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyPositions(int, java.lang.String!...!);
+    method public int[]! getFrames();
+    method public float[]! getPercentHeight();
+    method public float[]! getPercentWidth();
+    method public float[]! getPercentX();
+    method public float[]! getPercentY();
+    method public androidx.constraintlayout.core.dsl.KeyPositions.Type! getPositionType();
+    method public String![]! getTarget();
+    method public String! getTransitionEasing();
+    method public void setFrames(int...!);
+    method public void setPercentHeight(float...!);
+    method public void setPercentWidth(float...!);
+    method public void setPercentX(float...!);
+    method public void setPercentY(float...!);
+    method public void setPositionType(androidx.constraintlayout.core.dsl.KeyPositions.Type!);
+    method public void setTransitionEasing(String!);
+  }
+
+  public enum KeyPositions.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type CARTESIAN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type PATH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type SCREEN;
+  }
+
+  public class Keys {
+    ctor public Keys();
+    method protected void append(StringBuilder!, String!, float);
+    method protected void append(StringBuilder!, String!, float[]!);
+    method protected void append(StringBuilder!, String!, int);
+    method protected void append(StringBuilder!, String!, String!);
+    method protected void append(StringBuilder!, String!, String![]!);
+    method protected String! unpack(String![]!);
+  }
+
+  public class MotionScene {
+    ctor public MotionScene();
+    method public void addConstraintSet(androidx.constraintlayout.core.dsl.ConstraintSet!);
+    method public void addTransition(androidx.constraintlayout.core.dsl.Transition!);
+  }
+
+  public class OnSwipe {
+    ctor public OnSwipe();
+    ctor public OnSwipe(String!, androidx.constraintlayout.core.dsl.OnSwipe.Side!, androidx.constraintlayout.core.dsl.OnSwipe.Drag!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Mode! getAutoCompleteMode();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Drag! getDragDirection();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public String! getLimitBoundsTo();
+    method public float getMaxAcceleration();
+    method public float getMaxVelocity();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.TouchUp! getOnTouchUp();
+    method public String! getRotationCenterId();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Boundary! getSpringBoundary();
+    method public float getSpringDamping();
+    method public float getSpringMass();
+    method public float getSpringStiffness();
+    method public float getSpringStopThreshold();
+    method public String! getTouchAnchorId();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Side! getTouchAnchorSide();
+    method public void setAutoCompleteMode(androidx.constraintlayout.core.dsl.OnSwipe.Mode!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragDirection(androidx.constraintlayout.core.dsl.OnSwipe.Drag!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragScale(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragThreshold(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setLimitBoundsTo(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setMaxAcceleration(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setMaxVelocity(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setOnTouchUp(androidx.constraintlayout.core.dsl.OnSwipe.TouchUp!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setRotateCenter(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringBoundary(androidx.constraintlayout.core.dsl.OnSwipe.Boundary!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringDamping(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringMass(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringStiffness(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringStopThreshold(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setTouchAnchorId(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setTouchAnchorSide(androidx.constraintlayout.core.dsl.OnSwipe.Side!);
+    field public static final int FLAG_DISABLE_POST_SCROLL = 1; // 0x1
+    field public static final int FLAG_DISABLE_SCROLL = 2; // 0x2
+  }
+
+  public enum OnSwipe.Boundary {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_BOTH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary OVERSHOOT;
+  }
+
+  public enum OnSwipe.Drag {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag ANTICLOCKWISE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag CLOCKWISE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag DOWN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag UP;
+  }
+
+  public enum OnSwipe.Mode {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Mode SPRING;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Mode VELOCITY;
+  }
+
+  public enum OnSwipe.Side {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side MIDDLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side TOP;
+  }
+
+  public enum OnSwipe.TouchUp {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp AUTOCOMPLETE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp DECELERATE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp DECELERATE_COMPLETE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp NEVER_COMPLETE_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp NEVER_COMPLETE_START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp STOP;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp TO_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp TO_START;
+  }
+
+  public class Ref {
+    method public static void addStringToReferences(String!, java.util.ArrayList!);
+    method public String! getId();
+    method public float getPostMargin();
+    method public float getPreMargin();
+    method public float getWeight();
+    method public static float parseFloat(Object!);
+    method public static androidx.constraintlayout.core.dsl.Ref! parseStringToRef(String!);
+    method public void setId(String!);
+    method public void setPostMargin(float);
+    method public void setPreMargin(float);
+    method public void setWeight(float);
+  }
+
+  public class Transition {
+    ctor public Transition(String!, String!);
+    ctor public Transition(String!, String!, String!);
+    method public String! getId();
+    method public void setDuration(int);
+    method public void setFrom(String!);
+    method public void setId(String!);
+    method public void setKeyFrames(androidx.constraintlayout.core.dsl.Keys!);
+    method public void setOnSwipe(androidx.constraintlayout.core.dsl.OnSwipe!);
+    method public void setStagger(float);
+    method public void setTo(String!);
+  }
+
+  public class VChain extends androidx.constraintlayout.core.dsl.Chain {
+    ctor public VChain(String!);
+    ctor public VChain(String!, String!);
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getBaseline();
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getBottom();
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getTop();
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+  }
+
+  public class VChain.VAnchor extends androidx.constraintlayout.core.dsl.Chain.Anchor {
+  }
+
+  public class VGuideline extends androidx.constraintlayout.core.dsl.Guideline {
+    ctor public VGuideline(String!);
+    ctor public VGuideline(String!, String!);
+  }
+
+}
+
+package androidx.constraintlayout.core.motion {
+
+  public class CustomAttribute {
+    ctor public CustomAttribute(androidx.constraintlayout.core.motion.CustomAttribute!, Object!);
+    ctor public CustomAttribute(String!, androidx.constraintlayout.core.motion.CustomAttribute.AttributeType!);
+    ctor public CustomAttribute(String!, androidx.constraintlayout.core.motion.CustomAttribute.AttributeType!, Object!, boolean);
+    method public boolean diff(androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public androidx.constraintlayout.core.motion.CustomAttribute.AttributeType! getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public static int hsvToRgb(float, float, float);
+    method public boolean isContinuous();
+    method public int numberOfInterpolatedValues();
+    method public void setColorValue(int);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public enum CustomAttribute.AttributeType {
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType BOOLEAN_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType COLOR_DRAWABLE_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType COLOR_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType DIMENSION_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType FLOAT_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType INT_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType REFERENCE_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType STRING_TYPE;
+  }
+
+  public class CustomVariable {
+    ctor public CustomVariable(androidx.constraintlayout.core.motion.CustomVariable!);
+    ctor public CustomVariable(androidx.constraintlayout.core.motion.CustomVariable!, Object!);
+    ctor public CustomVariable(String!, int);
+    ctor public CustomVariable(String!, int, boolean);
+    ctor public CustomVariable(String!, int, float);
+    ctor public CustomVariable(String!, int, int);
+    ctor public CustomVariable(String!, int, Object!);
+    ctor public CustomVariable(String!, int, String!);
+    method public void applyToWidget(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public static String! colorString(int);
+    method public androidx.constraintlayout.core.motion.CustomVariable! copy();
+    method public boolean diff(androidx.constraintlayout.core.motion.CustomVariable!);
+    method public boolean getBooleanValue();
+    method public int getColorValue();
+    method public float getFloatValue();
+    method public int getIntegerValue();
+    method public int getInterpolatedColor(float[]!);
+    method public String! getName();
+    method public String! getStringValue();
+    method public int getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public static int hsvToRgb(float, float, float);
+    method public boolean isContinuous();
+    method public int numberOfInterpolatedValues();
+    method public static int rgbaTocColor(float, float, float, float);
+    method public void setBooleanValue(boolean);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setInterpolatedValue(androidx.constraintlayout.core.motion.MotionWidget!, float[]!);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public class Motion implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public Motion(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void addKey(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public int buildKeyFrames(float[]!, int[]!, int[]!);
+    method public void buildPath(float[]!, int);
+    method public void buildRect(float, float[]!, int);
+    method public String! getAnimateRelativeTo();
+    method public void getCenter(double, float[]!, float[]!);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public void getDpDt(float, float, float, float[]!);
+    method public int getDrawPath();
+    method public float getFinalHeight();
+    method public float getFinalWidth();
+    method public float getFinalX();
+    method public float getFinalY();
+    method public int getId(String!);
+    method public androidx.constraintlayout.core.motion.MotionPaths! getKeyFrame(int);
+    method public int getKeyFrameInfo(int, int[]!);
+    method public int getKeyFramePositions(int[]!, float[]!);
+    method public float getMotionStagger();
+    method public float getStartHeight();
+    method public float getStartWidth();
+    method public float getStartX();
+    method public float getStartY();
+    method public int getTransformPivotTarget();
+    method public androidx.constraintlayout.core.motion.MotionWidget! getView();
+    method public boolean interpolate(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+    method public void setDrawPath(int);
+    method public void setEnd(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setIdString(String!);
+    method public void setPathMotionArc(int);
+    method public void setStaggerOffset(float);
+    method public void setStaggerScale(float);
+    method public void setStart(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setStartState(androidx.constraintlayout.core.motion.utils.ViewState!, androidx.constraintlayout.core.motion.MotionWidget!, int, int, int);
+    method public void setTransformPivotTarget(int);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public void setView(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setup(int, int, float, long);
+    method public void setupRelative(androidx.constraintlayout.core.motion.Motion!);
+    field public static final int DRAW_PATH_AS_CONFIGURED = 4; // 0x4
+    field public static final int DRAW_PATH_BASIC = 1; // 0x1
+    field public static final int DRAW_PATH_CARTESIAN = 3; // 0x3
+    field public static final int DRAW_PATH_NONE = 0; // 0x0
+    field public static final int DRAW_PATH_RECTANGLE = 5; // 0x5
+    field public static final int DRAW_PATH_RELATIVE = 2; // 0x2
+    field public static final int DRAW_PATH_SCREEN = 6; // 0x6
+    field public static final int HORIZONTAL_PATH_X = 2; // 0x2
+    field public static final int HORIZONTAL_PATH_Y = 3; // 0x3
+    field public static final int PATH_PERCENT = 0; // 0x0
+    field public static final int PATH_PERPENDICULAR = 1; // 0x1
+    field public static final int ROTATION_LEFT = 2; // 0x2
+    field public static final int ROTATION_RIGHT = 1; // 0x1
+    field public static final int VERTICAL_PATH_X = 4; // 0x4
+    field public static final int VERTICAL_PATH_Y = 5; // 0x5
+    field public String! mId;
+  }
+
+  public class MotionPaths implements java.lang.Comparable {
+    ctor public MotionPaths();
+    ctor public MotionPaths(int, int, androidx.constraintlayout.core.motion.key.MotionKeyPosition!, androidx.constraintlayout.core.motion.MotionPaths!, androidx.constraintlayout.core.motion.MotionPaths!);
+    method public void applyParameters(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public int compareTo(androidx.constraintlayout.core.motion.MotionPaths!);
+    method public void configureRelativeTo(androidx.constraintlayout.core.motion.Motion!);
+    method public void setupRelative(androidx.constraintlayout.core.motion.Motion!, androidx.constraintlayout.core.motion.MotionPaths!);
+    field public static final int CARTESIAN = 0; // 0x0
+    field public static final boolean DEBUG = false;
+    field public static final boolean OLD_WAY = false;
+    field public static final int PERPENDICULAR = 1; // 0x1
+    field public static final int SCREEN = 2; // 0x2
+    field public static final String TAG = "MotionPaths";
+    field public String! mId;
+  }
+
+  public class MotionWidget implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public MotionWidget();
+    ctor public MotionWidget(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public androidx.constraintlayout.core.motion.MotionWidget! findViewById(int);
+    method public float getAlpha();
+    method public int getBottom();
+    method public androidx.constraintlayout.core.motion.CustomVariable! getCustomAttribute(String!);
+    method public java.util.Set! getCustomAttributeNames();
+    method public int getHeight();
+    method public int getId(String!);
+    method public int getLeft();
+    method public String! getName();
+    method public androidx.constraintlayout.core.motion.MotionWidget! getParent();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public int getRight();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getTop();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public float getValueAttributes(int);
+    method public int getVisibility();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getWidgetFrame();
+    method public int getWidth();
+    method public int getX();
+    method public int getY();
+    method public void layout(int, int, int, int);
+    method public void setBounds(int, int, int, int);
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setInterpolatedValue(androidx.constraintlayout.core.motion.CustomAttribute!, float[]!);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public boolean setValueAttributes(int, float);
+    method public boolean setValueMotion(int, float);
+    method public boolean setValueMotion(int, int);
+    method public boolean setValueMotion(int, String!);
+    method public void setVisibility(int);
+    method public void updateMotion(androidx.constraintlayout.core.motion.utils.TypedValues!);
+    field public static final int FILL_PARENT = -1; // 0xffffffff
+    field public static final int GONE_UNSET = -2147483648; // 0x80000000
+    field public static final int INVISIBLE = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VISIBILITY_MODE_IGNORE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_NORMAL = 0; // 0x0
+    field public static final int VISIBLE = 4; // 0x4
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public static class MotionWidget.Motion {
+    ctor public MotionWidget.Motion();
+    field public int mAnimateCircleAngleTo;
+    field public String! mAnimateRelativeTo;
+    field public int mDrawPath;
+    field public float mMotionStagger;
+    field public int mPathMotionArc;
+    field public float mPathRotate;
+    field public int mPolarRelativeTo;
+    field public int mQuantizeInterpolatorID;
+    field public String! mQuantizeInterpolatorString;
+    field public int mQuantizeInterpolatorType;
+    field public float mQuantizeMotionPhase;
+    field public int mQuantizeMotionSteps;
+    field public String! mTransitionEasing;
+  }
+
+  public static class MotionWidget.PropertySet {
+    ctor public MotionWidget.PropertySet();
+    field public float alpha;
+    field public float mProgress;
+    field public int mVisibilityMode;
+    field public int visibility;
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.key {
+
+  public class MotionConstraintSet {
+    ctor public MotionConstraintSet();
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public String! mIdString;
+    field public int mRotate;
+  }
+
+  public abstract class MotionKey implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public MotionKey();
+    method public abstract void addValues(java.util.HashMap!);
+    method public abstract androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public androidx.constraintlayout.core.motion.key.MotionKey! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public abstract void getAttributeNames(java.util.HashSet!);
+    method public int getFramePosition();
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setFramePosition(int);
+    method public void setInterpolation(java.util.HashMap!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! setViewId(int);
+    field public static final String ALPHA = "alpha";
+    field public static final String CUSTOM = "CUSTOM";
+    field public static final String ELEVATION = "elevation";
+    field public static final String ROTATION = "rotationZ";
+    field public static final String ROTATION_X = "rotationX";
+    field public static final String SCALE_X = "scaleX";
+    field public static final String SCALE_Y = "scaleY";
+    field public static final String TRANSITION_PATH_ROTATE = "transitionPathRotate";
+    field public static final String TRANSLATION_X = "translationX";
+    field public static final String TRANSLATION_Y = "translationY";
+    field public static int UNSET;
+    field public static final String VISIBILITY = "visibility";
+    field public java.util.HashMap! mCustom;
+    field public int mFramePosition;
+    field public int mType;
+  }
+
+  public class MotionKeyAttributes extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyAttributes();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getCurveFit();
+    method public int getId(String!);
+    method public void printAttributes();
+    field public static final int KEY_TYPE = 1; // 0x1
+  }
+
+  public class MotionKeyCycle extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyCycle();
+    method public void addCycleValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void dump();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    method public float getValue(String!);
+    method public void printAttributes();
+    field public static final int KEY_TYPE = 4; // 0x4
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class MotionKeyPosition extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyPosition();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    method public boolean intersects(int, int, androidx.constraintlayout.core.motion.utils.FloatRect!, androidx.constraintlayout.core.motion.utils.FloatRect!, float, float);
+    method public void positionAttributes(androidx.constraintlayout.core.motion.MotionWidget!, androidx.constraintlayout.core.motion.utils.FloatRect!, androidx.constraintlayout.core.motion.utils.FloatRect!, float, float, String![]!, float[]!);
+    field protected static final float SELECTION_SLOPE = 20.0f;
+    field public static final int TYPE_CARTESIAN = 0; // 0x0
+    field public static final int TYPE_PATH = 1; // 0x1
+    field public static final int TYPE_SCREEN = 2; // 0x2
+    field public float mAltPercentX;
+    field public float mAltPercentY;
+    field public int mCurveFit;
+    field public int mDrawPath;
+    field public int mPathMotionArc;
+    field public float mPercentHeight;
+    field public float mPercentWidth;
+    field public float mPercentX;
+    field public float mPercentY;
+    field public int mPositionType;
+    field public String! mTransitionEasing;
+  }
+
+  public class MotionKeyTimeCycle extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyTimeCycle();
+    method public void addTimeValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public androidx.constraintlayout.core.motion.key.MotionKeyTimeCycle! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    field public static final int KEY_TYPE = 3; // 0x3
+  }
+
+  public class MotionKeyTrigger extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyTrigger();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void conditionallyFire(float, androidx.constraintlayout.core.motion.MotionWidget!);
+    method public androidx.constraintlayout.core.motion.key.MotionKeyTrigger! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    field public static final String CROSS = "CROSS";
+    field public static final int KEY_TYPE = 5; // 0x5
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final int TYPE_CROSS = 312; // 0x138
+    field public static final int TYPE_NEGATIVE_CROSS = 310; // 0x136
+    field public static final int TYPE_POSITIVE_CROSS = 309; // 0x135
+    field public static final int TYPE_POST_LAYOUT = 304; // 0x130
+    field public static final int TYPE_TRIGGER_COLLISION_ID = 307; // 0x133
+    field public static final int TYPE_TRIGGER_COLLISION_VIEW = 306; // 0x132
+    field public static final int TYPE_TRIGGER_ID = 308; // 0x134
+    field public static final int TYPE_TRIGGER_RECEIVER = 311; // 0x137
+    field public static final int TYPE_TRIGGER_SLACK = 305; // 0x131
+    field public static final int TYPE_VIEW_TRANSITION_ON_CROSS = 301; // 0x12d
+    field public static final int TYPE_VIEW_TRANSITION_ON_NEGATIVE_CROSS = 303; // 0x12f
+    field public static final int TYPE_VIEW_TRANSITION_ON_POSITIVE_CROSS = 302; // 0x12e
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.parse {
+
+  public class KeyParser {
+    ctor public KeyParser();
+    method public static void main(String![]!);
+    method public static androidx.constraintlayout.core.motion.utils.TypedBundle! parseAttributes(String!);
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.utils {
+
+  public class ArcCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public ArcCurveFit(int[]!, double[]!, double[]![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+    field public static final int ARC_ABOVE = 5; // 0x5
+    field public static final int ARC_BELOW = 4; // 0x4
+    field public static final int ARC_START_FLIP = 3; // 0x3
+    field public static final int ARC_START_HORIZONTAL = 2; // 0x2
+    field public static final int ARC_START_LINEAR = 0; // 0x0
+    field public static final int ARC_START_VERTICAL = 1; // 0x1
+  }
+
+  public abstract class CurveFit {
+    ctor public CurveFit();
+    method public static androidx.constraintlayout.core.motion.utils.CurveFit! get(int, double[]!, double[]![]!);
+    method public static androidx.constraintlayout.core.motion.utils.CurveFit! getArc(int[]!, double[]!, double[]![]!);
+    method public abstract void getPos(double, double[]!);
+    method public abstract void getPos(double, float[]!);
+    method public abstract double getPos(double, int);
+    method public abstract void getSlope(double, double[]!);
+    method public abstract double getSlope(double, int);
+    method public abstract double[]! getTimePoints();
+    field public static final int CONSTANT = 2; // 0x2
+    field public static final int LINEAR = 1; // 0x1
+    field public static final int SPLINE = 0; // 0x0
+  }
+
+  public interface DifferentialInterpolator {
+    method public float getInterpolation(float);
+    method public float getVelocity();
+  }
+
+  public class Easing {
+    ctor public Easing();
+    method public double get(double);
+    method public double getDiff(double);
+    method public static androidx.constraintlayout.core.motion.utils.Easing! getInterpolator(String!);
+    field public static String![]! NAMED_EASING;
+  }
+
+  public class FloatRect {
+    ctor public FloatRect();
+    method public final float centerX();
+    method public final float centerY();
+    field public float bottom;
+    field public float left;
+    field public float right;
+    field public float top;
+  }
+
+  public class HyperSpline {
+    ctor public HyperSpline();
+    ctor public HyperSpline(double[]![]!);
+    method public double approxLength(androidx.constraintlayout.core.motion.utils.HyperSpline.Cubic![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getVelocity(double, double[]!);
+    method public void setup(double[]![]!);
+  }
+
+  public static class HyperSpline.Cubic {
+    ctor public HyperSpline.Cubic(double, double, double, double);
+    method public double eval(double);
+    method public double vel(double);
+  }
+
+  public class KeyCache {
+    ctor public KeyCache();
+    method public float getFloatValue(Object!, String!, int);
+    method public void setFloatValue(Object!, String!, int, float);
+  }
+
+  public abstract class KeyCycleOscillator {
+    ctor public KeyCycleOscillator();
+    method public float get(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public float getSlope(float);
+    method public static androidx.constraintlayout.core.motion.utils.KeyCycleOscillator! makeWidgetCycle(String!);
+    method protected void setCustom(Object!);
+    method public void setPoint(int, int, String!, int, float, float, float, float);
+    method public void setPoint(int, int, String!, int, float, float, float, float, Object!);
+    method public void setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float);
+    method public void setType(String!);
+    method public void setup(float);
+    method public boolean variesByPath();
+    field public int mVariesBy;
+  }
+
+  public static class KeyCycleOscillator.PathRotateSet extends androidx.constraintlayout.core.motion.utils.KeyCycleOscillator {
+    ctor public KeyCycleOscillator.PathRotateSet(String!);
+    method public void setPathRotate(androidx.constraintlayout.core.motion.MotionWidget!, float, double, double);
+  }
+
+  public class KeyFrameArray {
+    ctor public KeyFrameArray();
+  }
+
+  public static class KeyFrameArray.CustomArray {
+    ctor public KeyFrameArray.CustomArray();
+    method public void append(int, androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public void clear();
+    method public void dump();
+    method public int keyAt(int);
+    method public void remove(int);
+    method public int size();
+    method public androidx.constraintlayout.core.motion.CustomAttribute! valueAt(int);
+  }
+
+  public static class KeyFrameArray.CustomVar {
+    ctor public KeyFrameArray.CustomVar();
+    method public void append(int, androidx.constraintlayout.core.motion.CustomVariable!);
+    method public void clear();
+    method public void dump();
+    method public int keyAt(int);
+    method public void remove(int);
+    method public int size();
+    method public androidx.constraintlayout.core.motion.CustomVariable! valueAt(int);
+  }
+
+  public class LinearCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public LinearCurveFit(double[]!, double[]![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+  }
+
+  public class MonotonicCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public MonotonicCurveFit(double[]!, double[]![]!);
+    method public static androidx.constraintlayout.core.motion.utils.MonotonicCurveFit! buildWave(String!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+  }
+
+  public class Oscillator {
+    ctor public Oscillator();
+    method public void addPoint(double, float);
+    method public double getSlope(double, double, double);
+    method public double getValue(double, double);
+    method public void normalize();
+    method public void setType(int, String!);
+    field public static final int BOUNCE = 6; // 0x6
+    field public static final int COS_WAVE = 5; // 0x5
+    field public static final int CUSTOM = 7; // 0x7
+    field public static final int REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SAW_WAVE = 3; // 0x3
+    field public static final int SIN_WAVE = 0; // 0x0
+    field public static final int SQUARE_WAVE = 1; // 0x1
+    field public static String! TAG;
+    field public static final int TRIANGLE_WAVE = 2; // 0x2
+  }
+
+  public class Rect {
+    ctor public Rect();
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public class Schlick extends androidx.constraintlayout.core.motion.utils.Easing {
+  }
+
+  public abstract class SplineSet {
+    ctor public SplineSet();
+    method public float get(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public float getSlope(float);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeCustomSpline(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeCustomSplineSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeSpline(String!, long);
+    method public void setPoint(int, float);
+    method public void setProperty(androidx.constraintlayout.core.motion.utils.TypedValues!, float);
+    method public void setType(String!);
+    method public void setup(int);
+    field protected androidx.constraintlayout.core.motion.utils.CurveFit! mCurveFit;
+    field protected int[]! mTimePoints;
+    field protected float[]! mValues;
+  }
+
+  public static class SplineSet.CustomSet extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public SplineSet.CustomSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public void setProperty(androidx.constraintlayout.core.state.WidgetFrame!, float);
+  }
+
+  public static class SplineSet.CustomSpline extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public SplineSet.CustomSpline(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomVariable!);
+    method public void setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float);
+  }
+
+  public class SpringStopEngine implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public SpringStopEngine();
+    method public String! debug(String!, float);
+    method public float getAcceleration();
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+    method public void springConfig(float, float, float, float, float, float, float, int);
+  }
+
+  public class StepCurve extends androidx.constraintlayout.core.motion.utils.Easing {
+  }
+
+  public interface StopEngine {
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public class StopLogicEngine implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public StopLogicEngine();
+    method public void config(float, float, float, float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public static class StopLogicEngine.Decelerate implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public StopLogicEngine.Decelerate();
+    method public void config(float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public abstract class TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet();
+    method protected float calcWave(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public void setPoint(int, float, float, int, float);
+    method protected void setStartTime(long);
+    method public void setType(String!);
+    method public void setup(int);
+    field protected static final int CURVE_OFFSET = 2; // 0x2
+    field protected static final int CURVE_PERIOD = 1; // 0x1
+    field protected static final int CURVE_VALUE = 0; // 0x0
+    field protected float[]! mCache;
+    field protected boolean mContinue;
+    field protected int mCount;
+    field protected androidx.constraintlayout.core.motion.utils.CurveFit! mCurveFit;
+    field protected float mLastCycle;
+    field protected long mLastTime;
+    field protected int[]! mTimePoints;
+    field protected String! mType;
+    field protected float[]![]! mValues;
+    field protected int mWaveShape;
+    field protected static float sVal2PI;
+  }
+
+  public static class TimeCycleSplineSet.CustomSet extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet.CustomSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomAttribute!, float, int, float);
+    method public boolean setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class TimeCycleSplineSet.CustomVarSet extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet.CustomVarSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomVariable!, float, int, float);
+    method public boolean setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  protected static class TimeCycleSplineSet.Sort {
+    ctor protected TimeCycleSplineSet.Sort();
+  }
+
+  public class TypedBundle {
+    ctor public TypedBundle();
+    method public void add(int, boolean);
+    method public void add(int, float);
+    method public void add(int, int);
+    method public void add(int, String!);
+    method public void addIfNotNull(int, String!);
+    method public void applyDelta(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void applyDelta(androidx.constraintlayout.core.motion.utils.TypedValues!);
+    method public void clear();
+    method public int getInteger(int);
+  }
+
+  public interface TypedValues {
+    method public int getId(String!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    field public static final int BOOLEAN_MASK = 1; // 0x1
+    field public static final int FLOAT_MASK = 4; // 0x4
+    field public static final int INT_MASK = 2; // 0x2
+    field public static final int STRING_MASK = 8; // 0x8
+    field public static final String S_CUSTOM = "CUSTOM";
+    field public static final int TYPE_FRAME_POSITION = 100; // 0x64
+    field public static final int TYPE_TARGET = 101; // 0x65
+  }
+
+  public static interface TypedValues.AttributesType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyAttributes";
+    field public static final String S_ALPHA = "alpha";
+    field public static final String S_CURVE_FIT = "curveFit";
+    field public static final String S_CUSTOM = "CUSTOM";
+    field public static final String S_EASING = "easing";
+    field public static final String S_ELEVATION = "elevation";
+    field public static final String S_FRAME = "frame";
+    field public static final String S_PATH_ROTATE = "pathRotate";
+    field public static final String S_PIVOT_TARGET = "pivotTarget";
+    field public static final String S_PIVOT_X = "pivotX";
+    field public static final String S_PIVOT_Y = "pivotY";
+    field public static final String S_PROGRESS = "progress";
+    field public static final String S_ROTATION_X = "rotationX";
+    field public static final String S_ROTATION_Y = "rotationY";
+    field public static final String S_ROTATION_Z = "rotationZ";
+    field public static final String S_SCALE_X = "scaleX";
+    field public static final String S_SCALE_Y = "scaleY";
+    field public static final String S_TARGET = "target";
+    field public static final String S_TRANSLATION_X = "translationX";
+    field public static final String S_TRANSLATION_Y = "translationY";
+    field public static final String S_TRANSLATION_Z = "translationZ";
+    field public static final String S_VISIBILITY = "visibility";
+    field public static final int TYPE_ALPHA = 303; // 0x12f
+    field public static final int TYPE_CURVE_FIT = 301; // 0x12d
+    field public static final int TYPE_EASING = 317; // 0x13d
+    field public static final int TYPE_ELEVATION = 307; // 0x133
+    field public static final int TYPE_PATH_ROTATE = 316; // 0x13c
+    field public static final int TYPE_PIVOT_TARGET = 318; // 0x13e
+    field public static final int TYPE_PIVOT_X = 313; // 0x139
+    field public static final int TYPE_PIVOT_Y = 314; // 0x13a
+    field public static final int TYPE_PROGRESS = 315; // 0x13b
+    field public static final int TYPE_ROTATION_X = 308; // 0x134
+    field public static final int TYPE_ROTATION_Y = 309; // 0x135
+    field public static final int TYPE_ROTATION_Z = 310; // 0x136
+    field public static final int TYPE_SCALE_X = 311; // 0x137
+    field public static final int TYPE_SCALE_Y = 312; // 0x138
+    field public static final int TYPE_TRANSLATION_X = 304; // 0x130
+    field public static final int TYPE_TRANSLATION_Y = 305; // 0x131
+    field public static final int TYPE_TRANSLATION_Z = 306; // 0x132
+    field public static final int TYPE_VISIBILITY = 302; // 0x12e
+  }
+
+  public static interface TypedValues.Custom {
+    method public static int getId(String!);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Custom";
+    field public static final String S_BOOLEAN = "boolean";
+    field public static final String S_COLOR = "color";
+    field public static final String S_DIMENSION = "dimension";
+    field public static final String S_FLOAT = "float";
+    field public static final String S_INT = "integer";
+    field public static final String S_REFERENCE = "reference";
+    field public static final String S_STRING = "string";
+    field public static final int TYPE_BOOLEAN = 904; // 0x388
+    field public static final int TYPE_COLOR = 902; // 0x386
+    field public static final int TYPE_DIMENSION = 905; // 0x389
+    field public static final int TYPE_FLOAT = 901; // 0x385
+    field public static final int TYPE_INT = 900; // 0x384
+    field public static final int TYPE_REFERENCE = 906; // 0x38a
+    field public static final int TYPE_STRING = 903; // 0x387
+  }
+
+  public static interface TypedValues.CycleType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyCycle";
+    field public static final String S_ALPHA = "alpha";
+    field public static final String S_CURVE_FIT = "curveFit";
+    field public static final String S_CUSTOM_WAVE_SHAPE = "customWave";
+    field public static final String S_EASING = "easing";
+    field public static final String S_ELEVATION = "elevation";
+    field public static final String S_PATH_ROTATE = "pathRotate";
+    field public static final String S_PIVOT_X = "pivotX";
+    field public static final String S_PIVOT_Y = "pivotY";
+    field public static final String S_PROGRESS = "progress";
+    field public static final String S_ROTATION_X = "rotationX";
+    field public static final String S_ROTATION_Y = "rotationY";
+    field public static final String S_ROTATION_Z = "rotationZ";
+    field public static final String S_SCALE_X = "scaleX";
+    field public static final String S_SCALE_Y = "scaleY";
+    field public static final String S_TRANSLATION_X = "translationX";
+    field public static final String S_TRANSLATION_Y = "translationY";
+    field public static final String S_TRANSLATION_Z = "translationZ";
+    field public static final String S_VISIBILITY = "visibility";
+    field public static final String S_WAVE_OFFSET = "offset";
+    field public static final String S_WAVE_PERIOD = "period";
+    field public static final String S_WAVE_PHASE = "phase";
+    field public static final String S_WAVE_SHAPE = "waveShape";
+    field public static final int TYPE_ALPHA = 403; // 0x193
+    field public static final int TYPE_CURVE_FIT = 401; // 0x191
+    field public static final int TYPE_CUSTOM_WAVE_SHAPE = 422; // 0x1a6
+    field public static final int TYPE_EASING = 420; // 0x1a4
+    field public static final int TYPE_ELEVATION = 307; // 0x133
+    field public static final int TYPE_PATH_ROTATE = 416; // 0x1a0
+    field public static final int TYPE_PIVOT_X = 313; // 0x139
+    field public static final int TYPE_PIVOT_Y = 314; // 0x13a
+    field public static final int TYPE_PROGRESS = 315; // 0x13b
+    field public static final int TYPE_ROTATION_X = 308; // 0x134
+    field public static final int TYPE_ROTATION_Y = 309; // 0x135
+    field public static final int TYPE_ROTATION_Z = 310; // 0x136
+    field public static final int TYPE_SCALE_X = 311; // 0x137
+    field public static final int TYPE_SCALE_Y = 312; // 0x138
+    field public static final int TYPE_TRANSLATION_X = 304; // 0x130
+    field public static final int TYPE_TRANSLATION_Y = 305; // 0x131
+    field public static final int TYPE_TRANSLATION_Z = 306; // 0x132
+    field public static final int TYPE_VISIBILITY = 402; // 0x192
+    field public static final int TYPE_WAVE_OFFSET = 424; // 0x1a8
+    field public static final int TYPE_WAVE_PERIOD = 423; // 0x1a7
+    field public static final int TYPE_WAVE_PHASE = 425; // 0x1a9
+    field public static final int TYPE_WAVE_SHAPE = 421; // 0x1a5
+  }
+
+  public static interface TypedValues.MotionScene {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "MotionScene";
+    field public static final String S_DEFAULT_DURATION = "defaultDuration";
+    field public static final String S_LAYOUT_DURING_TRANSITION = "layoutDuringTransition";
+    field public static final int TYPE_DEFAULT_DURATION = 600; // 0x258
+    field public static final int TYPE_LAYOUT_DURING_TRANSITION = 601; // 0x259
+  }
+
+  public static interface TypedValues.MotionType {
+    method public static int getId(String!);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Motion";
+    field public static final String S_ANIMATE_CIRCLEANGLE_TO = "AnimateCircleAngleTo";
+    field public static final String S_ANIMATE_RELATIVE_TO = "AnimateRelativeTo";
+    field public static final String S_DRAW_PATH = "DrawPath";
+    field public static final String S_EASING = "TransitionEasing";
+    field public static final String S_PATHMOTION_ARC = "PathMotionArc";
+    field public static final String S_PATH_ROTATE = "PathRotate";
+    field public static final String S_POLAR_RELATIVETO = "PolarRelativeTo";
+    field public static final String S_QUANTIZE_INTERPOLATOR = "QuantizeInterpolator";
+    field public static final String S_QUANTIZE_INTERPOLATOR_ID = "QuantizeInterpolatorID";
+    field public static final String S_QUANTIZE_INTERPOLATOR_TYPE = "QuantizeInterpolatorType";
+    field public static final String S_QUANTIZE_MOTIONSTEPS = "QuantizeMotionSteps";
+    field public static final String S_QUANTIZE_MOTION_PHASE = "QuantizeMotionPhase";
+    field public static final String S_STAGGER = "Stagger";
+    field public static final int TYPE_ANIMATE_CIRCLEANGLE_TO = 606; // 0x25e
+    field public static final int TYPE_ANIMATE_RELATIVE_TO = 605; // 0x25d
+    field public static final int TYPE_DRAW_PATH = 608; // 0x260
+    field public static final int TYPE_EASING = 603; // 0x25b
+    field public static final int TYPE_PATHMOTION_ARC = 607; // 0x25f
+    field public static final int TYPE_PATH_ROTATE = 601; // 0x259
+    field public static final int TYPE_POLAR_RELATIVETO = 609; // 0x261
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR = 604; // 0x25c
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR_ID = 612; // 0x264
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR_TYPE = 611; // 0x263
+    field public static final int TYPE_QUANTIZE_MOTIONSTEPS = 610; // 0x262
+    field public static final int TYPE_QUANTIZE_MOTION_PHASE = 602; // 0x25a
+    field public static final int TYPE_STAGGER = 600; // 0x258
+  }
+
+  public static interface TypedValues.OnSwipe {
+    field public static final String AUTOCOMPLETE_MODE = "autocompletemode";
+    field public static final String![]! AUTOCOMPLETE_MODE_ENUM;
+    field public static final String DRAG_DIRECTION = "dragdirection";
+    field public static final String DRAG_SCALE = "dragscale";
+    field public static final String DRAG_THRESHOLD = "dragthreshold";
+    field public static final String LIMIT_BOUNDS_TO = "limitboundsto";
+    field public static final String MAX_ACCELERATION = "maxacceleration";
+    field public static final String MAX_VELOCITY = "maxvelocity";
+    field public static final String MOVE_WHEN_SCROLLAT_TOP = "movewhenscrollattop";
+    field public static final String NESTED_SCROLL_FLAGS = "nestedscrollflags";
+    field public static final String![]! NESTED_SCROLL_FLAGS_ENUM;
+    field public static final String ON_TOUCH_UP = "ontouchup";
+    field public static final String![]! ON_TOUCH_UP_ENUM;
+    field public static final String ROTATION_CENTER_ID = "rotationcenterid";
+    field public static final String SPRINGS_TOP_THRESHOLD = "springstopthreshold";
+    field public static final String SPRING_BOUNDARY = "springboundary";
+    field public static final String![]! SPRING_BOUNDARY_ENUM;
+    field public static final String SPRING_DAMPING = "springdamping";
+    field public static final String SPRING_MASS = "springmass";
+    field public static final String SPRING_STIFFNESS = "springstiffness";
+    field public static final String TOUCH_ANCHOR_ID = "touchanchorid";
+    field public static final String TOUCH_ANCHOR_SIDE = "touchanchorside";
+    field public static final String TOUCH_REGION_ID = "touchregionid";
+  }
+
+  public static interface TypedValues.PositionType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyPosition";
+    field public static final String S_DRAWPATH = "drawPath";
+    field public static final String S_PERCENT_HEIGHT = "percentHeight";
+    field public static final String S_PERCENT_WIDTH = "percentWidth";
+    field public static final String S_PERCENT_X = "percentX";
+    field public static final String S_PERCENT_Y = "percentY";
+    field public static final String S_SIZE_PERCENT = "sizePercent";
+    field public static final String S_TRANSITION_EASING = "transitionEasing";
+    field public static final int TYPE_CURVE_FIT = 508; // 0x1fc
+    field public static final int TYPE_DRAWPATH = 502; // 0x1f6
+    field public static final int TYPE_PATH_MOTION_ARC = 509; // 0x1fd
+    field public static final int TYPE_PERCENT_HEIGHT = 504; // 0x1f8
+    field public static final int TYPE_PERCENT_WIDTH = 503; // 0x1f7
+    field public static final int TYPE_PERCENT_X = 506; // 0x1fa
+    field public static final int TYPE_PERCENT_Y = 507; // 0x1fb
+    field public static final int TYPE_POSITION_TYPE = 510; // 0x1fe
+    field public static final int TYPE_SIZE_PERCENT = 505; // 0x1f9
+    field public static final int TYPE_TRANSITION_EASING = 501; // 0x1f5
+  }
+
+  public static interface TypedValues.TransitionType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Transitions";
+    field public static final String S_AUTO_TRANSITION = "autoTransition";
+    field public static final String S_DURATION = "duration";
+    field public static final String S_FROM = "from";
+    field public static final String S_INTERPOLATOR = "motionInterpolator";
+    field public static final String S_PATH_MOTION_ARC = "pathMotionArc";
+    field public static final String S_STAGGERED = "staggered";
+    field public static final String S_TO = "to";
+    field public static final String S_TRANSITION_FLAGS = "transitionFlags";
+    field public static final int TYPE_AUTO_TRANSITION = 704; // 0x2c0
+    field public static final int TYPE_DURATION = 700; // 0x2bc
+    field public static final int TYPE_FROM = 701; // 0x2bd
+    field public static final int TYPE_INTERPOLATOR = 705; // 0x2c1
+    field public static final int TYPE_PATH_MOTION_ARC = 509; // 0x1fd
+    field public static final int TYPE_STAGGERED = 706; // 0x2c2
+    field public static final int TYPE_TO = 702; // 0x2be
+    field public static final int TYPE_TRANSITION_FLAGS = 707; // 0x2c3
+  }
+
+  public static interface TypedValues.TriggerType {
+    method public static int getId(String!);
+    field public static final String CROSS = "CROSS";
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyTrigger";
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final int TYPE_CROSS = 312; // 0x138
+    field public static final int TYPE_NEGATIVE_CROSS = 310; // 0x136
+    field public static final int TYPE_POSITIVE_CROSS = 309; // 0x135
+    field public static final int TYPE_POST_LAYOUT = 304; // 0x130
+    field public static final int TYPE_TRIGGER_COLLISION_ID = 307; // 0x133
+    field public static final int TYPE_TRIGGER_COLLISION_VIEW = 306; // 0x132
+    field public static final int TYPE_TRIGGER_ID = 308; // 0x134
+    field public static final int TYPE_TRIGGER_RECEIVER = 311; // 0x137
+    field public static final int TYPE_TRIGGER_SLACK = 305; // 0x131
+    field public static final int TYPE_VIEW_TRANSITION_ON_CROSS = 301; // 0x12d
+    field public static final int TYPE_VIEW_TRANSITION_ON_NEGATIVE_CROSS = 303; // 0x12f
+    field public static final int TYPE_VIEW_TRANSITION_ON_POSITIVE_CROSS = 302; // 0x12e
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+  public class Utils {
+    ctor public Utils();
+    method public int getInterpolatedColor(float[]!);
+    method public static void log(String!);
+    method public static void log(String!, String!);
+    method public static void logStack(String!, int);
+    method public static void loge(String!, String!);
+    method public static int rgbaTocColor(float, float, float, float);
+    method public static void setDebugHandle(androidx.constraintlayout.core.motion.utils.Utils.DebugHandle!);
+    method public static void socketSend(String!);
+  }
+
+  public static interface Utils.DebugHandle {
+    method public void message(String!);
+  }
+
+  public class VelocityMatrix {
+    ctor public VelocityMatrix();
+    method public void applyTransform(float, float, int, int, float[]!);
+    method public void clear();
+    method public void setRotationVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setRotationVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+    method public void setScaleVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setScaleVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+    method public void setTranslationVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setTranslationVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+  }
+
+  public class ViewState {
+    ctor public ViewState();
+    method public void getState(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public float rotation;
+    field public int top;
+  }
+
+}
+
+package androidx.constraintlayout.core.parser {
+
+  public class CLArray extends androidx.constraintlayout.core.parser.CLContainer {
+    ctor public CLArray(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+  }
+
+  public class CLContainer extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLContainer(char[]!);
+    method public void add(androidx.constraintlayout.core.parser.CLElement!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public void clear();
+    method public androidx.constraintlayout.core.parser.CLContainer clone();
+    method public androidx.constraintlayout.core.parser.CLElement! get(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLElement! get(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArray(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArray(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArrayOrCreate(String!);
+    method public androidx.constraintlayout.core.parser.CLArray! getArrayOrNull(String!);
+    method public boolean getBoolean(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public boolean getBoolean(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloat(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloat(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloatOrNaN(String!);
+    method public int getInt(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public int getInt(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObject(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObject(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObjectOrNull(String!);
+    method public androidx.constraintlayout.core.parser.CLElement! getOrNull(int);
+    method public androidx.constraintlayout.core.parser.CLElement! getOrNull(String!);
+    method public String! getString(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public String! getString(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public String! getStringOrNull(int);
+    method public String! getStringOrNull(String!);
+    method public boolean has(String!);
+    method public java.util.ArrayList! names();
+    method public void put(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public void putNumber(String!, float);
+    method public void putString(String!, String!);
+    method public void remove(String!);
+    method public int size();
+  }
+
+  public class CLElement implements java.lang.Cloneable {
+    ctor public CLElement(char[]!);
+    method protected void addIndent(StringBuilder!, int);
+    method public androidx.constraintlayout.core.parser.CLElement clone();
+    method public String! content();
+    method public androidx.constraintlayout.core.parser.CLElement! getContainer();
+    method protected String! getDebugName();
+    method public long getEnd();
+    method public float getFloat();
+    method public int getInt();
+    method public int getLine();
+    method public long getStart();
+    method protected String! getStrClass();
+    method public boolean hasContent();
+    method public boolean isDone();
+    method public boolean isStarted();
+    method public boolean notStarted();
+    method public void setContainer(androidx.constraintlayout.core.parser.CLContainer!);
+    method public void setEnd(long);
+    method public void setLine(int);
+    method public void setStart(long);
+    method protected String! toFormattedJSON(int, int);
+    method protected String! toJSON();
+    field protected androidx.constraintlayout.core.parser.CLContainer! mContainer;
+    field protected long mEnd;
+    field protected long mStart;
+    field protected static int sBaseIndent;
+    field protected static int sMaxLine;
+  }
+
+  public class CLKey extends androidx.constraintlayout.core.parser.CLContainer {
+    ctor public CLKey(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public String! getName();
+    method public androidx.constraintlayout.core.parser.CLElement! getValue();
+    method public void set(androidx.constraintlayout.core.parser.CLElement!);
+  }
+
+  public class CLNumber extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLNumber(char[]!);
+    ctor public CLNumber(float);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public boolean isInt();
+    method public void putValue(float);
+  }
+
+  public class CLObject extends androidx.constraintlayout.core.parser.CLContainer implements java.lang.Iterable {
+    ctor public CLObject(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLObject! allocate(char[]!);
+    method public androidx.constraintlayout.core.parser.CLObject clone();
+    method public java.util.Iterator! iterator();
+    method public String! toFormattedJSON();
+    method public String! toFormattedJSON(int, int);
+    method public String! toJSON();
+  }
+
+  public class CLParser {
+    ctor public CLParser(String!);
+    method public androidx.constraintlayout.core.parser.CLObject! parse() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static androidx.constraintlayout.core.parser.CLObject! parse(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+  }
+
+  public class CLParsingException extends java.lang.Exception {
+    ctor public CLParsingException(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public String! reason();
+  }
+
+  public class CLString extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLString(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLString from(String);
+  }
+
+  public class CLToken extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLToken(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public boolean getBoolean() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLToken.Type! getType();
+    method public boolean isNull() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public boolean validate(char, long);
+  }
+
+}
+
+package androidx.constraintlayout.core.state {
+
+  public class ConstraintReference implements androidx.constraintlayout.core.state.Reference {
+    ctor public ConstraintReference(androidx.constraintlayout.core.state.State!);
+    method public void addCustomColor(String!, int);
+    method public void addCustomFloat(String!, float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! alpha(float);
+    method public void apply();
+    method public void applyWidgetConstraints();
+    method public androidx.constraintlayout.core.state.ConstraintReference! baseline();
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToBaseline(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottom();
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottomToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottomToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! centerHorizontally(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! centerVertically(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! circularConstraint(Object!, float, float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! clear();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearAll();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearHorizontal();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearVertical();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! createConstraintWidget();
+    method public androidx.constraintlayout.core.state.ConstraintReference! end();
+    method public androidx.constraintlayout.core.state.ConstraintReference! endToEnd(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! endToStart(Object!);
+    method public float getAlpha();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public androidx.constraintlayout.core.state.Dimension! getHeight();
+    method public int getHorizontalChainStyle();
+    method public float getHorizontalChainWeight();
+    method public Object! getKey();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public String! getTag();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public int getVerticalChainStyle(int);
+    method public float getVerticalChainWeight();
+    method public Object! getView();
+    method public androidx.constraintlayout.core.state.Dimension! getWidth();
+    method public androidx.constraintlayout.core.state.ConstraintReference! height(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! horizontalBias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! left();
+    method public androidx.constraintlayout.core.state.ConstraintReference! leftToLeft(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! leftToRight(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! margin(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! margin(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! marginGone(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! marginGone(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! pivotX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! pivotY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! right();
+    method public androidx.constraintlayout.core.state.ConstraintReference! rightToLeft(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rightToRight(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationZ(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! scaleX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! scaleY(float);
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setFacade(androidx.constraintlayout.core.state.helpers.Facade!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! setHeight(androidx.constraintlayout.core.state.Dimension!);
+    method public void setHorizontalChainStyle(int);
+    method public void setHorizontalChainWeight(float);
+    method public void setKey(Object!);
+    method public void setTag(String!);
+    method public void setVerticalChainStyle(int);
+    method public void setVerticalChainWeight(float);
+    method public void setView(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! setWidth(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! start();
+    method public androidx.constraintlayout.core.state.ConstraintReference! startToEnd(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! startToStart(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! top();
+    method public androidx.constraintlayout.core.state.ConstraintReference! topToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! topToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationZ(float);
+    method public void validate() throws java.lang.Exception;
+    method public androidx.constraintlayout.core.state.ConstraintReference! verticalBias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! visibility(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! width(androidx.constraintlayout.core.state.Dimension!);
+    field protected Object! mBottomToBottom;
+    field protected Object! mBottomToTop;
+    field protected Object! mEndToEnd;
+    field protected Object! mEndToStart;
+    field protected float mHorizontalBias;
+    field protected Object! mLeftToLeft;
+    field protected Object! mLeftToRight;
+    field protected int mMarginBottom;
+    field protected int mMarginBottomGone;
+    field protected int mMarginEnd;
+    field protected int mMarginEndGone;
+    field protected int mMarginLeft;
+    field protected int mMarginLeftGone;
+    field protected int mMarginRight;
+    field protected int mMarginRightGone;
+    field protected int mMarginStart;
+    field protected int mMarginStartGone;
+    field protected int mMarginTop;
+    field protected int mMarginTopGone;
+    field protected Object! mRightToLeft;
+    field protected Object! mRightToRight;
+    field protected Object! mStartToEnd;
+    field protected Object! mStartToStart;
+    field protected Object! mTopToBottom;
+    field protected Object! mTopToTop;
+    field protected float mVerticalBias;
+  }
+
+  public static interface ConstraintReference.ConstraintReferenceFactory {
+    method public androidx.constraintlayout.core.state.ConstraintReference! create(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class ConstraintSetParser {
+    ctor public ConstraintSetParser();
+    method public static void parseDesignElementsJSON(String!, java.util.ArrayList!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseJSON(String!, androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.ConstraintSetParser.LayoutVariables!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseJSON(String!, androidx.constraintlayout.core.state.Transition!, int);
+    method public static void parseMotionSceneJSON(androidx.constraintlayout.core.state.CoreMotionScene!, String!);
+  }
+
+  public static class ConstraintSetParser.DesignElement {
+    method public String! getId();
+    method public java.util.HashMap! getParams();
+    method public String! getType();
+  }
+
+  public static class ConstraintSetParser.LayoutVariables {
+    ctor public ConstraintSetParser.LayoutVariables();
+    method public void putOverride(String!, float);
+  }
+
+  public enum ConstraintSetParser.MotionLayoutDebugFlags {
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags NONE;
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags SHOW_ALL;
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags UNKNOWN;
+  }
+
+  public interface CoreMotionScene {
+    method public String! getConstraintSet(int);
+    method public String! getConstraintSet(String!);
+    method public String! getTransition(String!);
+    method public void setConstraintSetContent(String!, String!);
+    method public void setDebugName(String!);
+    method public void setTransitionContent(String!, String!);
+  }
+
+  public interface CorePixelDp {
+    method public float toPixels(float);
+  }
+
+  public class Dimension {
+    method public void apply(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public static androidx.constraintlayout.core.state.Dimension! createFixed(int);
+    method public static androidx.constraintlayout.core.state.Dimension! createFixed(Object!);
+    method public static androidx.constraintlayout.core.state.Dimension! createParent();
+    method public static androidx.constraintlayout.core.state.Dimension! createPercent(Object!, float);
+    method public static androidx.constraintlayout.core.state.Dimension! createRatio(String!);
+    method public static androidx.constraintlayout.core.state.Dimension! createSpread();
+    method public static androidx.constraintlayout.core.state.Dimension! createSuggested(int);
+    method public static androidx.constraintlayout.core.state.Dimension! createSuggested(Object!);
+    method public static androidx.constraintlayout.core.state.Dimension! createWrap();
+    method public boolean equalsFixedValue(int);
+    method public androidx.constraintlayout.core.state.Dimension! fixed(int);
+    method public androidx.constraintlayout.core.state.Dimension! fixed(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! max(int);
+    method public androidx.constraintlayout.core.state.Dimension! max(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! min(int);
+    method public androidx.constraintlayout.core.state.Dimension! min(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! percent(Object!, float);
+    method public androidx.constraintlayout.core.state.Dimension! ratio(String!);
+    method public androidx.constraintlayout.core.state.Dimension! suggested(int);
+    method public androidx.constraintlayout.core.state.Dimension! suggested(Object!);
+    field public static final Object! FIXED_DIMENSION;
+    field public static final Object! PARENT_DIMENSION;
+    field public static final Object! PERCENT_DIMENSION;
+    field public static final Object! RATIO_DIMENSION;
+    field public static final Object! SPREAD_DIMENSION;
+    field public static final Object! WRAP_DIMENSION;
+  }
+
+  public enum Dimension.Type {
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type FIXED;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type MATCH_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type MATCH_PARENT;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type WRAP;
+  }
+
+  public class HelperReference extends androidx.constraintlayout.core.state.ConstraintReference implements androidx.constraintlayout.core.state.helpers.Facade {
+    ctor public HelperReference(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.State.Helper!);
+    method public androidx.constraintlayout.core.state.HelperReference! add(java.lang.Object!...!);
+    method public void applyBase();
+    method public androidx.constraintlayout.core.widgets.HelperWidget! getHelperWidget();
+    method public androidx.constraintlayout.core.state.State.Helper! getType();
+    method public void setHelperWidget(androidx.constraintlayout.core.widgets.HelperWidget!);
+    field protected final androidx.constraintlayout.core.state.State! mHelperState;
+    field protected java.util.ArrayList! mReferences;
+  }
+
+  public interface Interpolator {
+    method public float getInterpolation(float);
+  }
+
+  public interface Reference {
+    method public void apply();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public Object! getKey();
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setKey(Object!);
+  }
+
+  public class Registry {
+    ctor public Registry();
+    method public String! currentContent(String!);
+    method public String! currentLayoutInformation(String!);
+    method public static androidx.constraintlayout.core.state.Registry! getInstance();
+    method public long getLastModified(String!);
+    method public java.util.Set! getLayoutList();
+    method public void register(String!, androidx.constraintlayout.core.state.RegistryCallback!);
+    method public void setDrawDebug(String!, int);
+    method public void setLayoutInformationMode(String!, int);
+    method public void unregister(String!, androidx.constraintlayout.core.state.RegistryCallback!);
+    method public void updateContent(String!, String!);
+    method public void updateDimensions(String!, int, int);
+    method public void updateProgress(String!, float);
+  }
+
+  public interface RegistryCallback {
+    method public String! currentLayoutInformation();
+    method public String! currentMotionScene();
+    method public long getLastModified();
+    method public void onDimensions(int, int);
+    method public void onNewMotionScene(String!);
+    method public void onProgress(float);
+    method public void setDrawDebug(int);
+    method public void setLayoutInformationMode(int);
+  }
+
+  public class State {
+    ctor public State();
+    method public void apply(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public androidx.constraintlayout.core.state.helpers.BarrierReference! barrier(Object!, androidx.constraintlayout.core.state.State.Direction!);
+    method public void baselineNeededFor(Object!);
+    method public androidx.constraintlayout.core.state.helpers.AlignHorizontallyReference! centerHorizontally(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.AlignVerticallyReference! centerVertically(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! constraints(Object!);
+    method public int convertDimension(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! createConstraintReference(Object!);
+    method public void directMapping();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getFlow(Object!, boolean);
+    method public androidx.constraintlayout.core.state.helpers.GridReference getGrid(Object, String);
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getHorizontalFlow();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getHorizontalFlow(java.lang.Object!...!);
+    method public java.util.ArrayList! getIdsForTag(String!);
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getVerticalFlow();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getVerticalFlow(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! guideline(Object!, int);
+    method public androidx.constraintlayout.core.state.State! height(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.HelperReference! helper(Object!, androidx.constraintlayout.core.state.State.Helper!);
+    method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain();
+    method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! horizontalGuideline(Object!);
+    method public boolean isBaselineNeeded(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method @Deprecated public boolean isLtr();
+    method public boolean isRtl();
+    method public void map(Object!, Object!);
+    method public void reset();
+    method public boolean sameFixedHeight(int);
+    method public boolean sameFixedWidth(int);
+    method public void setDpToPixel(androidx.constraintlayout.core.state.CorePixelDp!);
+    method public androidx.constraintlayout.core.state.State! setHeight(androidx.constraintlayout.core.state.Dimension!);
+    method @Deprecated public void setLtr(boolean);
+    method public void setRtl(boolean);
+    method public void setTag(String!, String!);
+    method public androidx.constraintlayout.core.state.State! setWidth(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain();
+    method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! verticalGuideline(Object!);
+    method public androidx.constraintlayout.core.state.State! width(androidx.constraintlayout.core.state.Dimension!);
+    field public static final Integer PARENT;
+    field protected java.util.HashMap! mHelperReferences;
+    field public final androidx.constraintlayout.core.state.ConstraintReference! mParent;
+    field protected java.util.HashMap! mReferences;
+  }
+
+  public enum State.Chain {
+    method public static androidx.constraintlayout.core.state.State.Chain! getChainByString(String!);
+    method public static int getValueByString(String!);
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain PACKED;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain SPREAD_INSIDE;
+    field public static java.util.Map! chainMap;
+    field public static java.util.Map! valueMap;
+  }
+
+  public enum State.Constraint {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_TOP;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_TOP;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CENTER_HORIZONTALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CENTER_VERTICALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CIRCULAR_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint END_TO_END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint END_TO_START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint LEFT_TO_LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint LEFT_TO_RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint RIGHT_TO_LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint RIGHT_TO_RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint START_TO_END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint START_TO_START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_TOP;
+  }
+
+  public enum State.Direction {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction TOP;
+  }
+
+  public enum State.Helper {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ALIGN_HORIZONTALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ALIGN_VERTICALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper BARRIER;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper COLUMN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper FLOW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper GRID;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper HORIZONTAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper HORIZONTAL_FLOW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper LAYER;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ROW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper VERTICAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper VERTICAL_FLOW;
+  }
+
+  public enum State.Wrap {
+    method public static androidx.constraintlayout.core.state.State.Wrap! getChainByString(String!);
+    method public static int getValueByString(String!);
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap ALIGNED;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap NONE;
+    field public static java.util.Map! valueMap;
+    field public static java.util.Map! wrapMap;
+  }
+
+  public class Transition implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public Transition(androidx.constraintlayout.core.state.CorePixelDp);
+    method public void addCustomColor(int, String!, String!, int);
+    method public void addCustomFloat(int, String!, String!, float);
+    method public void addKeyAttribute(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyAttribute(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!, androidx.constraintlayout.core.motion.CustomVariable![]!);
+    method public void addKeyCycle(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyPosition(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyPosition(String!, int, int, float, float);
+    method public void calcStagger();
+    method public void clear();
+    method public boolean contains(String!);
+    method public float dragToProgress(float, int, int, float, float);
+    method public void fillKeyPositions(androidx.constraintlayout.core.state.WidgetFrame!, float[]!, float[]!, float[]!);
+    method public androidx.constraintlayout.core.state.Transition.KeyPosition! findNextPosition(String!, int);
+    method public androidx.constraintlayout.core.state.Transition.KeyPosition! findPreviousPosition(String!, int);
+    method public int getAutoTransition();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getEnd(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getEnd(String!);
+    method public int getId(String!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getInterpolated(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getInterpolated(String!);
+    method public int getInterpolatedHeight();
+    method public int getInterpolatedWidth();
+    method public androidx.constraintlayout.core.state.Interpolator! getInterpolator();
+    method public static androidx.constraintlayout.core.state.Interpolator! getInterpolator(int, String!);
+    method public int getKeyFrames(String!, float[]!, int[]!, int[]!);
+    method public androidx.constraintlayout.core.motion.Motion! getMotion(String!);
+    method public int getNumberKeyPositions(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public float[]! getPath(String!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getStart(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getStart(String!);
+    method public float getTouchUpProgress(long);
+    method public androidx.constraintlayout.core.state.Transition.WidgetState! getWidgetState(String!, androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public boolean hasOnSwipe();
+    method public boolean hasPositionKeyframes();
+    method public void interpolate(int, int, float);
+    method public boolean isEmpty();
+    method public boolean isTouchNotDone(float);
+    method public void setTouchUp(float, long, float, float);
+    method public void setTransitionProperties(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public void updateFrom(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int);
+    field public static final int END = 1; // 0x1
+    field public static final int INTERPOLATED = 2; // 0x2
+    field public static final int START = 0; // 0x0
+  }
+
+  public static class Transition.WidgetState {
+    ctor public Transition.WidgetState();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getFrame(int);
+    method public void interpolate(int, int, float, androidx.constraintlayout.core.state.Transition!);
+    method public void setKeyAttribute(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setKeyAttribute(androidx.constraintlayout.core.motion.utils.TypedBundle!, androidx.constraintlayout.core.motion.CustomVariable![]!);
+    method public void setKeyCycle(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setKeyPosition(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setPathRelative(androidx.constraintlayout.core.state.Transition.WidgetState!);
+    method public void update(androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+  }
+
+  public class TransitionParser {
+    ctor public TransitionParser();
+    method @Deprecated public static void parse(androidx.constraintlayout.core.parser.CLObject!, androidx.constraintlayout.core.state.Transition!, androidx.constraintlayout.core.state.CorePixelDp!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseKeyFrames(androidx.constraintlayout.core.parser.CLObject!, androidx.constraintlayout.core.state.Transition!) throws androidx.constraintlayout.core.parser.CLParsingException;
+  }
+
+  public class WidgetFrame {
+    ctor public WidgetFrame();
+    ctor public WidgetFrame(androidx.constraintlayout.core.state.WidgetFrame!);
+    ctor public WidgetFrame(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void addCustomColor(String!, int);
+    method public void addCustomFloat(String!, float);
+    method public float centerX();
+    method public float centerY();
+    method public boolean containsCustom(String);
+    method public androidx.constraintlayout.core.motion.CustomVariable! getCustomAttribute(String!);
+    method public java.util.Set! getCustomAttributeNames();
+    method public int getCustomColor(String!);
+    method public float getCustomFloat(String!);
+    method public String! getId();
+    method public androidx.constraintlayout.core.motion.utils.TypedBundle! getMotionProperties();
+    method public int height();
+    method public static void interpolate(int, int, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.Transition!, float);
+    method public boolean isDefaultTransform();
+    method public StringBuilder! serialize(StringBuilder!);
+    method public StringBuilder! serialize(StringBuilder!, boolean);
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setCustomValue(androidx.constraintlayout.core.motion.CustomAttribute!, float[]!);
+    method public boolean setValue(String!, androidx.constraintlayout.core.parser.CLElement!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.state.WidgetFrame! update();
+    method public androidx.constraintlayout.core.state.WidgetFrame! update(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void updateAttributes(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public int width();
+    field public float alpha;
+    field public int bottom;
+    field public float interpolatedPos;
+    field public int left;
+    field public String! name;
+    field public static float phone_orientation;
+    field public float pivotX;
+    field public float pivotY;
+    field public int right;
+    field public float rotationX;
+    field public float rotationY;
+    field public float rotationZ;
+    field public float scaleX;
+    field public float scaleY;
+    field public int top;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+    field public int visibility;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget! widget;
+  }
+
+}
+
+package androidx.constraintlayout.core.state.helpers {
+
+  public class AlignHorizontallyReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public AlignHorizontallyReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class AlignVerticallyReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public AlignVerticallyReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class BarrierReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public BarrierReference(androidx.constraintlayout.core.state.State!);
+    method public void setBarrierDirection(androidx.constraintlayout.core.state.State.Direction!);
+  }
+
+  public class ChainReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public ChainReference(androidx.constraintlayout.core.state.State, androidx.constraintlayout.core.state.State.Helper);
+    method public void addChainElement(String, float, float, float);
+    method public androidx.constraintlayout.core.state.helpers.ChainReference bias(float);
+    method public float getBias();
+    method protected float getPostMargin(String);
+    method protected float getPreMargin(String);
+    method public androidx.constraintlayout.core.state.State.Chain getStyle();
+    method protected float getWeight(String);
+    method public androidx.constraintlayout.core.state.helpers.ChainReference style(androidx.constraintlayout.core.state.State.Chain);
+    field protected float mBias;
+    field @Deprecated protected java.util.HashMap mMapPostMargin;
+    field @Deprecated protected java.util.HashMap mMapPreMargin;
+    field @Deprecated protected java.util.HashMap mMapWeights;
+    field protected androidx.constraintlayout.core.state.State.Chain mStyle;
+  }
+
+  public interface Facade {
+    method public void apply();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+  }
+
+  public class FlowReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public FlowReference(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.State.Helper!);
+    method public void addFlowElement(String!, float, float, float);
+    method public float getFirstHorizontalBias();
+    method public int getFirstHorizontalStyle();
+    method public float getFirstVerticalBias();
+    method public int getFirstVerticalStyle();
+    method public int getHorizontalAlign();
+    method public float getHorizontalBias();
+    method public int getHorizontalGap();
+    method public int getHorizontalStyle();
+    method public float getLastHorizontalBias();
+    method public int getLastHorizontalStyle();
+    method public float getLastVerticalBias();
+    method public int getLastVerticalStyle();
+    method public int getMaxElementsWrap();
+    method public int getOrientation();
+    method public int getPaddingBottom();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingTop();
+    method protected float getPostMargin(String!);
+    method protected float getPreMargin(String!);
+    method public int getVerticalAlign();
+    method public float getVerticalBias();
+    method public int getVerticalGap();
+    method public int getVerticalStyle();
+    method protected float getWeight(String!);
+    method public int getWrapMode();
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingTop(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field protected float mFirstHorizontalBias;
+    field protected int mFirstHorizontalStyle;
+    field protected float mFirstVerticalBias;
+    field protected int mFirstVerticalStyle;
+    field protected androidx.constraintlayout.core.widgets.Flow! mFlow;
+    field protected int mHorizontalAlign;
+    field protected int mHorizontalGap;
+    field protected int mHorizontalStyle;
+    field protected float mLastHorizontalBias;
+    field protected int mLastHorizontalStyle;
+    field protected float mLastVerticalBias;
+    field protected int mLastVerticalStyle;
+    field protected java.util.HashMap! mMapPostMargin;
+    field protected java.util.HashMap! mMapPreMargin;
+    field protected java.util.HashMap! mMapWeights;
+    field protected int mMaxElementsWrap;
+    field protected int mOrientation;
+    field protected int mPaddingBottom;
+    field protected int mPaddingLeft;
+    field protected int mPaddingRight;
+    field protected int mPaddingTop;
+    field protected int mVerticalAlign;
+    field protected int mVerticalGap;
+    field protected int mVerticalStyle;
+    field protected int mWrapMode;
+  }
+
+  public class GridReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public GridReference(androidx.constraintlayout.core.state.State, androidx.constraintlayout.core.state.State.Helper);
+    method public String? getColumnWeights();
+    method public int getColumnsSet();
+    method public int getFlags();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public int getPaddingBottom();
+    method public int getPaddingEnd();
+    method public int getPaddingStart();
+    method public int getPaddingTop();
+    method public String? getRowWeights();
+    method public int getRowsSet();
+    method public String? getSkips();
+    method public String? getSpans();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String);
+    method public void setColumnsSet(int);
+    method public void setFlags(int);
+    method public void setFlags(String);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingEnd(int);
+    method public void setPaddingStart(int);
+    method public void setPaddingTop(int);
+    method public void setRowWeights(String);
+    method public void setRowsSet(int);
+    method public void setSkips(String);
+    method public void setSpans(String);
+    method public void setVerticalGaps(float);
+  }
+
+  public class GuidelineReference implements androidx.constraintlayout.core.state.helpers.Facade androidx.constraintlayout.core.state.Reference {
+    ctor public GuidelineReference(androidx.constraintlayout.core.state.State!);
+    method public void apply();
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! end(Object!);
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public Object! getKey();
+    method public int getOrientation();
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! percent(float);
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setKey(Object!);
+    method public void setOrientation(int);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! start(Object!);
+  }
+
+  public class HorizontalChainReference extends androidx.constraintlayout.core.state.helpers.ChainReference {
+    ctor public HorizontalChainReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class VerticalChainReference extends androidx.constraintlayout.core.state.helpers.ChainReference {
+    ctor public VerticalChainReference(androidx.constraintlayout.core.state.State!);
+  }
+
+}
+
+package androidx.constraintlayout.core.utils {
+
+  public class GridCore extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public GridCore();
+    ctor public GridCore(int, int);
+    method public String? getColumnWeights();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidgetContainer? getContainer();
+    method public int getFlags();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public String? getRowWeights();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String);
+    method public void setColumns(int);
+    method public void setContainer(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer);
+    method public void setFlags(int);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setRowWeights(String);
+    method public void setRows(int);
+    method public void setSkips(String);
+    method public void setSpans(CharSequence);
+    method public void setVerticalGaps(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int SPANS_RESPECT_WIDGET_ORDER = 2; // 0x2
+    field public static final int SUB_GRID_BY_COL_ROW = 1; // 0x1
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridEngine {
+    ctor public GridEngine();
+    ctor public GridEngine(int, int);
+    ctor public GridEngine(int, int, int);
+    method public int bottomOfWidget(int);
+    method public int leftOfWidget(int);
+    method public int rightOfWidget(int);
+    method public void setColumns(int);
+    method public void setNumWidgets(int);
+    method public void setOrientation(int);
+    method public void setRows(int);
+    method public void setSkips(String!);
+    method public void setSpans(CharSequence!);
+    method public void setup();
+    method public int topOfWidget(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+}
+
+package androidx.constraintlayout.core.widgets {
+
+  public class Barrier extends androidx.constraintlayout.core.widgets.HelperWidget {
+    ctor public Barrier();
+    ctor public Barrier(String!);
+    method public boolean allSolved();
+    method @Deprecated public boolean allowsGoneWidget();
+    method public boolean getAllowsGoneWidget();
+    method public int getBarrierType();
+    method public int getMargin();
+    method public int getOrientation();
+    method protected void markWidgets();
+    method public void setAllowsGoneWidget(boolean);
+    method public void setBarrierType(int);
+    method public void setMargin(int);
+    field public static final int BOTTOM = 3; // 0x3
+    field public static final int LEFT = 0; // 0x0
+    field public static final int RIGHT = 1; // 0x1
+    field public static final int TOP = 2; // 0x2
+  }
+
+  public class Chain {
+    ctor public Chain();
+    method public static void applyChainConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, java.util.ArrayList!, int);
+    field public static final boolean USE_CHAIN_OPTIMIZATION = false;
+  }
+
+  public class ChainHead {
+    ctor public ChainHead(androidx.constraintlayout.core.widgets.ConstraintWidget!, int, boolean);
+    method public void define();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirst();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirstMatchConstraintWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirstVisibleWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getHead();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLast();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLastMatchConstraintWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLastVisibleWidget();
+    method public float getTotalWeight();
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirst;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirstMatchConstraintWidget;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirstVisibleWidget;
+    field protected boolean mHasComplexMatchWeights;
+    field protected boolean mHasDefinedWeights;
+    field protected boolean mHasRatio;
+    field protected boolean mHasUndefinedWeights;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mHead;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLast;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLastMatchConstraintWidget;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLastVisibleWidget;
+    field protected float mTotalWeight;
+    field protected java.util.ArrayList! mWeightedMatchConstraintsWidgets;
+    field protected int mWidgetsCount;
+    field protected int mWidgetsMatchCount;
+  }
+
+  public class ConstraintAnchor {
+    ctor public ConstraintAnchor(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public boolean connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public boolean connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int, int, boolean);
+    method public void copyFrom(androidx.constraintlayout.core.widgets.ConstraintAnchor!, java.util.HashMap!);
+    method public void findDependents(int, java.util.ArrayList!, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public java.util.HashSet! getDependents();
+    method public int getFinalValue();
+    method public int getMargin();
+    method public final androidx.constraintlayout.core.widgets.ConstraintAnchor! getOpposite();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getOwner();
+    method public androidx.constraintlayout.core.SolverVariable! getSolverVariable();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getTarget();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor.Type! getType();
+    method public boolean hasCenteredDependents();
+    method public boolean hasDependents();
+    method public boolean hasFinalValue();
+    method public boolean isConnected();
+    method public boolean isConnectionAllowed(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public boolean isConnectionAllowed(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isSideAnchor();
+    method public boolean isSimilarDimensionConnection(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isValidConnection(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isVerticalAnchor();
+    method public void reset();
+    method public void resetFinalResolution();
+    method public void resetSolverVariable(androidx.constraintlayout.core.Cache!);
+    method public void setFinalValue(int);
+    method public void setGoneMargin(int);
+    method public void setMargin(int);
+    field public int mMargin;
+    field public final androidx.constraintlayout.core.widgets.ConstraintWidget! mOwner;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mTarget;
+    field public final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type! mType;
+  }
+
+  public enum ConstraintAnchor.Type {
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER_X;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER_Y;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type LEFT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type NONE;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type TOP;
+  }
+
+  public class ConstraintWidget {
+    ctor public ConstraintWidget();
+    ctor public ConstraintWidget(int, int);
+    ctor public ConstraintWidget(int, int, int, int);
+    ctor public ConstraintWidget(String!);
+    ctor public ConstraintWidget(String!, int, int);
+    ctor public ConstraintWidget(String!, int, int, int, int);
+    method public void addChildrenToSolverByDependency(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, java.util.HashSet!, int, boolean);
+    method public void addToSolver(androidx.constraintlayout.core.LinearSystem!, boolean);
+    method public boolean allowedInBarrier();
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int);
+    method public void connectCircularConstraint(androidx.constraintlayout.core.widgets.ConstraintWidget!, float, int);
+    method public void copy(androidx.constraintlayout.core.widgets.ConstraintWidget!, java.util.HashMap!);
+    method public void createObjectVariables(androidx.constraintlayout.core.LinearSystem!);
+    method public void ensureMeasureRequested();
+    method public void ensureWidgetRuns();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getAnchor(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public java.util.ArrayList! getAnchors();
+    method public int getBaselineDistance();
+    method public float getBiasPercent(int);
+    method public int getBottom();
+    method public Object! getCompanionWidget();
+    method public int getContainerItemSkip();
+    method public String! getDebugName();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getDimensionBehaviour(int);
+    method public float getDimensionRatio();
+    method public int getDimensionRatioSide();
+    method public boolean getHasBaseline();
+    method public int getHeight();
+    method public float getHorizontalBiasPercent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getHorizontalChainControlWidget();
+    method public int getHorizontalChainStyle();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getHorizontalDimensionBehaviour();
+    method public int getHorizontalMargin();
+    method public int getLastHorizontalMeasureSpec();
+    method public int getLastVerticalMeasureSpec();
+    method public int getLeft();
+    method public int getLength(int);
+    method public int getMaxHeight();
+    method public int getMaxWidth();
+    method public int getMinHeight();
+    method public int getMinWidth();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getNextChainMember(int);
+    method public int getOptimizerWrapHeight();
+    method public int getOptimizerWrapWidth();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getParent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getPreviousChainMember(int);
+    method public int getRight();
+    method protected int getRootX();
+    method protected int getRootY();
+    method public androidx.constraintlayout.core.widgets.analyzer.WidgetRun! getRun(int);
+    method public void getSceneString(StringBuilder!);
+    method public int getTop();
+    method public String! getType();
+    method public float getVerticalBiasPercent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getVerticalChainControlWidget();
+    method public int getVerticalChainStyle();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getVerticalDimensionBehaviour();
+    method public int getVerticalMargin();
+    method public int getVisibility();
+    method public int getWidth();
+    method public int getWrapBehaviorInParent();
+    method public int getX();
+    method public int getY();
+    method public boolean hasBaseline();
+    method public boolean hasDanglingDimension(int);
+    method public boolean hasDependencies();
+    method public boolean hasDimensionOverride();
+    method public boolean hasResolvedTargets(int, int);
+    method public void immediateConnect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int, int);
+    method public boolean isAnimated();
+    method public boolean isHeightWrapContent();
+    method public boolean isHorizontalSolvingPassDone();
+    method public boolean isInBarrier(int);
+    method public boolean isInHorizontalChain();
+    method public boolean isInPlaceholder();
+    method public boolean isInVerticalChain();
+    method public boolean isInVirtualLayout();
+    method public boolean isMeasureRequested();
+    method public boolean isResolvedHorizontally();
+    method public boolean isResolvedVertically();
+    method public boolean isRoot();
+    method public boolean isSpreadHeight();
+    method public boolean isSpreadWidth();
+    method public boolean isVerticalSolvingPassDone();
+    method public boolean isWidthWrapContent();
+    method public void markHorizontalSolvingPassDone();
+    method public void markVerticalSolvingPassDone();
+    method public boolean oppositeDimensionDependsOn(int);
+    method public boolean oppositeDimensionsTied();
+    method public void reset();
+    method public void resetAllConstraints();
+    method public void resetAnchor(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void resetAnchors();
+    method public void resetFinalResolution();
+    method public void resetSolverVariables(androidx.constraintlayout.core.Cache!);
+    method public void resetSolvingPassFlag();
+    method public StringBuilder! serialize(StringBuilder!);
+    method public void setAnimated(boolean);
+    method public void setBaselineDistance(int);
+    method public void setCompanionWidget(Object!);
+    method public void setContainerItemSkip(int);
+    method public void setDebugName(String!);
+    method public void setDebugSolverName(androidx.constraintlayout.core.LinearSystem!, String!);
+    method public void setDimension(int, int);
+    method public void setDimensionRatio(float, int);
+    method public void setDimensionRatio(String!);
+    method public void setFinalBaseline(int);
+    method public void setFinalFrame(int, int, int, int, int, int);
+    method public void setFinalHorizontal(int, int);
+    method public void setFinalLeft(int);
+    method public void setFinalTop(int);
+    method public void setFinalVertical(int, int);
+    method public void setFrame(int, int, int);
+    method public void setFrame(int, int, int, int);
+    method public void setGoneMargin(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int);
+    method public void setHasBaseline(boolean);
+    method public void setHeight(int);
+    method public void setHeightWrapContent(boolean);
+    method public void setHorizontalBiasPercent(float);
+    method public void setHorizontalChainStyle(int);
+    method public void setHorizontalDimension(int, int);
+    method public void setHorizontalDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public void setHorizontalMatchStyle(int, int, int, float);
+    method public void setHorizontalWeight(float);
+    method protected void setInBarrier(int, boolean);
+    method public void setInPlaceholder(boolean);
+    method public void setInVirtualLayout(boolean);
+    method public void setLastMeasureSpec(int, int);
+    method public void setLength(int, int);
+    method public void setMaxHeight(int);
+    method public void setMaxWidth(int);
+    method public void setMeasureRequested(boolean);
+    method public void setMinHeight(int);
+    method public void setMinWidth(int);
+    method public void setOffset(int, int);
+    method public void setOrigin(int, int);
+    method public void setParent(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setType(String!);
+    method public void setVerticalBiasPercent(float);
+    method public void setVerticalChainStyle(int);
+    method public void setVerticalDimension(int, int);
+    method public void setVerticalDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public void setVerticalMatchStyle(int, int, int, float);
+    method public void setVerticalWeight(float);
+    method public void setVisibility(int);
+    method public void setWidth(int);
+    method public void setWidthWrapContent(boolean);
+    method public void setWrapBehaviorInParent(int);
+    method public void setX(int);
+    method public void setY(int);
+    method public void setupDimensionRatio(boolean, boolean, boolean, boolean);
+    method public void updateFromRuns(boolean, boolean);
+    method public void updateFromSolver(androidx.constraintlayout.core.LinearSystem!, boolean);
+    field public static final int ANCHOR_BASELINE = 4; // 0x4
+    field public static final int ANCHOR_BOTTOM = 3; // 0x3
+    field public static final int ANCHOR_LEFT = 0; // 0x0
+    field public static final int ANCHOR_RIGHT = 1; // 0x1
+    field public static final int ANCHOR_TOP = 2; // 0x2
+    field public static final int BOTH = 2; // 0x2
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static float DEFAULT_BIAS;
+    field protected static final int DIRECT = 2; // 0x2
+    field public static final int GONE = 8; // 0x8
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVISIBLE = 4; // 0x4
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_RATIO = 3; // 0x3
+    field public static final int MATCH_CONSTRAINT_RATIO_RESOLVED = 4; // 0x4
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field protected static final int SOLVER = 1; // 0x1
+    field public static final int UNKNOWN = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VISIBLE = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_HORIZONTAL_ONLY = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_INCLUDED = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_SKIPPED = 3; // 0x3
+    field public static final int WRAP_BEHAVIOR_VERTICAL_ONLY = 2; // 0x2
+    field public androidx.constraintlayout.core.state.WidgetFrame! frame;
+    field public androidx.constraintlayout.core.widgets.analyzer.ChainRun! horizontalChainRun;
+    field public int horizontalGroup;
+    field public boolean[]! isTerminalWidget;
+    field protected java.util.ArrayList! mAnchors;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mBaseline;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mBottom;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mCenter;
+    field public float mCircleConstraintAngle;
+    field public float mDimensionRatio;
+    field protected int mDimensionRatioSide;
+    field public int mHorizontalResolution;
+    field public androidx.constraintlayout.core.widgets.analyzer.HorizontalWidgetRun! mHorizontalRun;
+    field public boolean mIsHeightWrapContent;
+    field public boolean mIsWidthWrapContent;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mLeft;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor![]! mListAnchors;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour![]! mListDimensionBehaviors;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget![]! mListNextMatchConstraintsWidget;
+    field public int mMatchConstraintDefaultHeight;
+    field public int mMatchConstraintDefaultWidth;
+    field public int mMatchConstraintMaxHeight;
+    field public int mMatchConstraintMaxWidth;
+    field public int mMatchConstraintMinHeight;
+    field public int mMatchConstraintMinWidth;
+    field public float mMatchConstraintPercentHeight;
+    field public float mMatchConstraintPercentWidth;
+    field protected int mMinHeight;
+    field protected int mMinWidth;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget![]! mNextChainWidget;
+    field protected int mOffsetX;
+    field protected int mOffsetY;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget! mParent;
+    field public int[]! mResolvedMatchConstraintDefault;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mRight;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mTop;
+    field public int mVerticalResolution;
+    field public androidx.constraintlayout.core.widgets.analyzer.VerticalWidgetRun! mVerticalRun;
+    field public float[]! mWeight;
+    field protected int mX;
+    field protected int mY;
+    field public boolean measured;
+    field public androidx.constraintlayout.core.widgets.analyzer.WidgetRun![]! run;
+    field public String! stringId;
+    field public androidx.constraintlayout.core.widgets.analyzer.ChainRun! verticalChainRun;
+    field public int verticalGroup;
+  }
+
+  public enum ConstraintWidget.DimensionBehaviour {
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour FIXED;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour MATCH_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour MATCH_PARENT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour WRAP_CONTENT;
+  }
+
+  public class ConstraintWidgetContainer extends androidx.constraintlayout.core.widgets.WidgetContainer {
+    ctor public ConstraintWidgetContainer();
+    ctor public ConstraintWidgetContainer(int, int);
+    ctor public ConstraintWidgetContainer(int, int, int, int);
+    ctor public ConstraintWidgetContainer(String!, int, int);
+    method public boolean addChildrenToSolver(androidx.constraintlayout.core.LinearSystem!);
+    method public void addHorizontalWrapMaxVariable(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void addHorizontalWrapMinVariable(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void defineTerminalWidgets();
+    method public boolean directMeasure(boolean);
+    method public boolean directMeasureSetup(boolean);
+    method public boolean directMeasureWithOrientation(boolean, int);
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method public java.util.ArrayList! getHorizontalGuidelines();
+    method public androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer! getMeasurer();
+    method public int getOptimizationLevel();
+    method public androidx.constraintlayout.core.LinearSystem! getSystem();
+    method public java.util.ArrayList! getVerticalGuidelines();
+    method public boolean handlesInternalConstraints();
+    method public void invalidateGraph();
+    method public void invalidateMeasures();
+    method public boolean isHeightMeasuredTooSmall();
+    method public boolean isRtl();
+    method public boolean isWidthMeasuredTooSmall();
+    method public static boolean measure(int, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure!, int);
+    method public long measure(int, int, int, int, int, int, int, int, int);
+    method public boolean optimizeFor(int);
+    method public void setMeasurer(androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+    method public void setOptimizationLevel(int);
+    method public void setPadding(int, int, int, int);
+    method public void setPass(int);
+    method public void setRtl(boolean);
+    method public boolean updateChildrenFromSolver(androidx.constraintlayout.core.LinearSystem!, boolean[]!);
+    method public void updateHierarchy();
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyGraph! mDependencyGraph;
+    field public boolean mGroupsWrapOptimized;
+    field public int mHorizontalChainsSize;
+    field public boolean mHorizontalWrapOptimized;
+    field public androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure! mMeasure;
+    field protected androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer! mMeasurer;
+    field public androidx.constraintlayout.core.Metrics! mMetrics;
+    field public boolean mSkipSolver;
+    field protected androidx.constraintlayout.core.LinearSystem! mSystem;
+    field public int mVerticalChainsSize;
+    field public boolean mVerticalWrapOptimized;
+    field public int mWrapFixedHeight;
+    field public int mWrapFixedWidth;
+  }
+
+  public class Flow extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public Flow();
+    method public float getMaxElementsWrap();
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalBias(float);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int HORIZONTAL_ALIGN_END = 1; // 0x1
+    field public static final int HORIZONTAL_ALIGN_START = 0; // 0x0
+    field public static final int VERTICAL_ALIGN_BASELINE = 3; // 0x3
+    field public static final int VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int VERTICAL_ALIGN_TOP = 0; // 0x0
+    field public static final int WRAP_ALIGNED = 2; // 0x2
+    field public static final int WRAP_CHAIN = 1; // 0x1
+    field public static final int WRAP_CHAIN_NEW = 3; // 0x3
+    field public static final int WRAP_NONE = 0; // 0x0
+  }
+
+  public class Guideline extends androidx.constraintlayout.core.widgets.ConstraintWidget {
+    ctor public Guideline();
+    method public void cyclePosition();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getAnchor();
+    method public int getMinimumPosition();
+    method public int getOrientation();
+    method public int getRelativeBegin();
+    method public int getRelativeBehaviour();
+    method public int getRelativeEnd();
+    method public float getRelativePercent();
+    method public boolean isPercent();
+    method public void setFinalValue(int);
+    method public void setGuideBegin(int);
+    method public void setGuideEnd(int);
+    method public void setGuidePercent(float);
+    method public void setGuidePercent(int);
+    method public void setMinimumPosition(int);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int RELATIVE_BEGIN = 1; // 0x1
+    field public static final int RELATIVE_END = 2; // 0x2
+    field public static final int RELATIVE_PERCENT = 0; // 0x0
+    field public static final int RELATIVE_UNKNOWN = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field protected boolean mGuidelineUseRtl;
+    field protected int mRelativeBegin;
+    field protected int mRelativeEnd;
+    field protected float mRelativePercent;
+  }
+
+  public interface Helper {
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void removeAllIds();
+    method public void updateConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+  }
+
+  public class HelperWidget extends androidx.constraintlayout.core.widgets.ConstraintWidget implements androidx.constraintlayout.core.widgets.Helper {
+    ctor public HelperWidget();
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void addDependents(java.util.ArrayList!, int, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public int findGroupInDependents(int);
+    method public void removeAllIds();
+    method public void updateConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget![]! mWidgets;
+    field public int mWidgetsCount;
+  }
+
+  public class Optimizer {
+    ctor public Optimizer();
+    method public static final boolean enabled(int, int);
+    field public static final int OPTIMIZATION_BARRIER = 2; // 0x2
+    field public static final int OPTIMIZATION_CACHE_MEASURES = 256; // 0x100
+    field public static final int OPTIMIZATION_CHAIN = 4; // 0x4
+    field public static final int OPTIMIZATION_DEPENDENCY_ORDERING = 512; // 0x200
+    field public static final int OPTIMIZATION_DIMENSIONS = 8; // 0x8
+    field public static final int OPTIMIZATION_DIRECT = 1; // 0x1
+    field public static final int OPTIMIZATION_GRAPH = 64; // 0x40
+    field public static final int OPTIMIZATION_GRAPH_WRAP = 128; // 0x80
+    field public static final int OPTIMIZATION_GROUPING = 1024; // 0x400
+    field public static final int OPTIMIZATION_GROUPS = 32; // 0x20
+    field public static final int OPTIMIZATION_NONE = 0; // 0x0
+    field public static final int OPTIMIZATION_RATIO = 16; // 0x10
+    field public static final int OPTIMIZATION_STANDARD = 257; // 0x101
+  }
+
+  public class Placeholder extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public Placeholder();
+  }
+
+  public class Rectangle {
+    ctor public Rectangle();
+    method public boolean contains(int, int);
+    method public int getCenterX();
+    method public int getCenterY();
+    method public void setBounds(int, int, int, int);
+    field public int height;
+    field public int width;
+    field public int x;
+    field public int y;
+  }
+
+  public class VirtualLayout extends androidx.constraintlayout.core.widgets.HelperWidget {
+    ctor public VirtualLayout();
+    method public void applyRtl(boolean);
+    method public void captureWidgets();
+    method public boolean contains(java.util.HashSet!);
+    method public int getMeasuredHeight();
+    method public int getMeasuredWidth();
+    method public int getPaddingBottom();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingTop();
+    method protected void measure(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, int, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, int);
+    method public void measure(int, int, int, int);
+    method protected boolean measureChildren();
+    method public boolean needSolverPass();
+    method protected void needsCallbackFromSolver(boolean);
+    method public void setMeasure(int, int);
+    method public void setPadding(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingEnd(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingStart(int);
+    method public void setPaddingTop(int);
+    field protected androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure! mMeasure;
+  }
+
+  public class WidgetContainer extends androidx.constraintlayout.core.widgets.ConstraintWidget {
+    ctor public WidgetContainer();
+    ctor public WidgetContainer(int, int);
+    ctor public WidgetContainer(int, int, int, int);
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!...!);
+    method public java.util.ArrayList! getChildren();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidgetContainer! getRootConstraintContainer();
+    method public void layout();
+    method public void remove(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void removeAllChildren();
+    field public java.util.ArrayList! mChildren;
+  }
+
+}
+
+package androidx.constraintlayout.core.widgets.analyzer {
+
+  public class BasicMeasure {
+    ctor public BasicMeasure(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public long solverMeasure(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int, int, int, int, int, int, int);
+    method public void updateHierarchy(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    field public static final int AT_MOST = -2147483648; // 0x80000000
+    field public static final int EXACTLY = 1073741824; // 0x40000000
+    field public static final int FIXED = -3; // 0xfffffffd
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int UNSPECIFIED = 0; // 0x0
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public static class BasicMeasure.Measure {
+    ctor public BasicMeasure.Measure();
+    field public static int SELF_DIMENSIONS;
+    field public static int TRY_GIVEN_DIMENSIONS;
+    field public static int USE_GIVEN_DIMENSIONS;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! horizontalBehavior;
+    field public int horizontalDimension;
+    field public int measureStrategy;
+    field public int measuredBaseline;
+    field public boolean measuredHasBaseline;
+    field public int measuredHeight;
+    field public boolean measuredNeedsSolverPass;
+    field public int measuredWidth;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! verticalBehavior;
+    field public int verticalDimension;
+  }
+
+  public static interface BasicMeasure.Measurer {
+    method public void didMeasures();
+    method public void measure(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure!);
+  }
+
+  public class ChainRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public ChainRun(androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public void applyToWidget();
+  }
+
+  public interface Dependency {
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+  }
+
+  public class DependencyGraph {
+    ctor public DependencyGraph(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public void buildGraph();
+    method public void buildGraph(java.util.ArrayList!);
+    method public void defineTerminalWidgets(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public boolean directMeasure(boolean);
+    method public boolean directMeasureSetup(boolean);
+    method public boolean directMeasureWithOrientation(boolean, int);
+    method public void invalidateGraph();
+    method public void invalidateMeasures();
+    method public void measureWidgets();
+    method public void setMeasurer(androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+  }
+
+  public class DependencyNode implements androidx.constraintlayout.core.widgets.analyzer.Dependency {
+    ctor public DependencyNode(androidx.constraintlayout.core.widgets.analyzer.WidgetRun!);
+    method public void addDependency(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method public void clear();
+    method public String! name();
+    method public void resolve(int);
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    field public boolean delegateToWidgetRun;
+    field public boolean readyToSolve;
+    field public boolean resolved;
+    field public androidx.constraintlayout.core.widgets.analyzer.Dependency! updateDelegate;
+    field public int value;
+  }
+
+  public class Direct {
+    ctor public Direct();
+    method public static String! ls(int);
+    method public static boolean solveChain(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, int, int, androidx.constraintlayout.core.widgets.ChainHead!, boolean, boolean, boolean);
+    method public static void solvingPass(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+  }
+
+  public class Grouping {
+    ctor public Grouping();
+    method public static androidx.constraintlayout.core.widgets.analyzer.WidgetGroup! findDependents(androidx.constraintlayout.core.widgets.ConstraintWidget!, int, java.util.ArrayList!, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public static boolean simpleSolvingPass(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+    method public static boolean validInGroup(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+  }
+
+  public class HorizontalWidgetRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public HorizontalWidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void applyToWidget();
+  }
+
+  public class VerticalWidgetRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public VerticalWidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void applyToWidget();
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! baseline;
+  }
+
+  public class WidgetGroup {
+    ctor public WidgetGroup(int);
+    method public boolean add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void apply();
+    method public void cleanup(java.util.ArrayList!);
+    method public void clear();
+    method public int getId();
+    method public int getOrientation();
+    method public boolean intersectWith(androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public boolean isAuthoritative();
+    method public int measureWrap(androidx.constraintlayout.core.LinearSystem!, int);
+    method public void moveTo(int, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public void setAuthoritative(boolean);
+    method public void setOrientation(int);
+    method public int size();
+  }
+
+  public abstract class WidgetRun implements androidx.constraintlayout.core.widgets.analyzer.Dependency {
+    ctor public WidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method protected final void addTarget(androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, int);
+    method protected final void addTarget(androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, int, androidx.constraintlayout.core.widgets.analyzer.DimensionDependency!);
+    method protected final int getLimitedDimension(int, int);
+    method protected final androidx.constraintlayout.core.widgets.analyzer.DependencyNode! getTarget(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method protected final androidx.constraintlayout.core.widgets.analyzer.DependencyNode! getTarget(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public long getWrapDimension();
+    method public boolean isCenterConnection();
+    method public boolean isDimensionResolved();
+    method public boolean isResolved();
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method protected void updateRunCenter(androidx.constraintlayout.core.widgets.analyzer.Dependency!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method protected void updateRunEnd(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method protected void updateRunStart(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method public long wrapSize(int);
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! end;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! mDimensionBehavior;
+    field protected androidx.constraintlayout.core.widgets.analyzer.WidgetRun.RunType! mRunType;
+    field public int matchConstraintsType;
+    field public int orientation;
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! start;
+  }
+
+}
+
diff --git a/constraintlayout/constraintlayout-core/api/restricted_1.1.0-beta01.txt b/constraintlayout/constraintlayout-core/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..daaf9e5
--- /dev/null
+++ b/constraintlayout/constraintlayout-core/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,3397 @@
+// Signature format: 4.0
+package androidx.constraintlayout.core {
+
+  public class ArrayLinkedVariables implements androidx.constraintlayout.core.ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public final void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public final float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public int getHead();
+    method public final int getId(int);
+    method public final int getNextIndice(int);
+    method public final float getValue(int);
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public final void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public final float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+    field protected final androidx.constraintlayout.core.Cache! mCache;
+  }
+
+  public class ArrayRow {
+    ctor public ArrayRow();
+    ctor public ArrayRow(androidx.constraintlayout.core.Cache!);
+    method public androidx.constraintlayout.core.ArrayRow! addError(androidx.constraintlayout.core.LinearSystem!, int);
+    method public void addError(androidx.constraintlayout.core.SolverVariable!);
+    method public void clear();
+    method public androidx.constraintlayout.core.ArrayRow! createRowDimensionRatio(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEqualDimension(float, float, float, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEqualMatchDimensions(float, float, float, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEquals(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowEquals(androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowGreaterThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowGreaterThan(androidx.constraintlayout.core.SolverVariable!, int, androidx.constraintlayout.core.SolverVariable!);
+    method public androidx.constraintlayout.core.ArrayRow! createRowLowerThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.ArrayRow! createRowWithAngle(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.SolverVariable! getKey();
+    method public androidx.constraintlayout.core.SolverVariable! getPivotCandidate(androidx.constraintlayout.core.LinearSystem!, boolean[]!);
+    method public void initFromRow(androidx.constraintlayout.core.LinearSystem.Row!);
+    method public boolean isEmpty();
+    method public androidx.constraintlayout.core.SolverVariable! pickPivot(androidx.constraintlayout.core.SolverVariable!);
+    method public void reset();
+    method public void updateFromFinalVariable(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public void updateFromRow(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.ArrayRow!, boolean);
+    method public void updateFromSynonymVariable(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public void updateFromSystem(androidx.constraintlayout.core.LinearSystem!);
+    field public androidx.constraintlayout.core.ArrayRow.ArrayRowVariables! variables;
+  }
+
+  public static interface ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+  }
+
+  public class Cache {
+    ctor public Cache();
+  }
+
+  public class GoalRow extends androidx.constraintlayout.core.ArrayRow {
+    ctor public GoalRow(androidx.constraintlayout.core.Cache!);
+  }
+
+  public class LinearSystem {
+    ctor public LinearSystem();
+    method public void addCenterPoint(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintWidget!, float, int);
+    method public void addCentering(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, float, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addConstraint(androidx.constraintlayout.core.ArrayRow!);
+    method public androidx.constraintlayout.core.ArrayRow! addEquality(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addEquality(androidx.constraintlayout.core.SolverVariable!, int);
+    method public void addGreaterBarrier(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, boolean);
+    method public void addGreaterThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addLowerBarrier(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, boolean);
+    method public void addLowerThan(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int, int);
+    method public void addRatio(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float, int);
+    method public void addSynonym(androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, int);
+    method public androidx.constraintlayout.core.SolverVariable! createErrorVariable(int, String!);
+    method public androidx.constraintlayout.core.SolverVariable! createExtraVariable();
+    method public androidx.constraintlayout.core.SolverVariable! createObjectVariable(Object!);
+    method public androidx.constraintlayout.core.ArrayRow! createRow();
+    method public static androidx.constraintlayout.core.ArrayRow! createRowDimensionPercent(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public androidx.constraintlayout.core.SolverVariable! createSlackVariable();
+    method public void displayReadableRows();
+    method public void displayVariablesReadableRows();
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method public androidx.constraintlayout.core.Cache! getCache();
+    method public int getMemoryUsed();
+    method public static androidx.constraintlayout.core.Metrics! getMetrics();
+    method public int getNumEquations();
+    method public int getNumVariables();
+    method public int getObjectVariableValue(Object!);
+    method public void minimize() throws java.lang.Exception;
+    method public void removeRow(androidx.constraintlayout.core.ArrayRow!);
+    method public void reset();
+    field public static long ARRAY_ROW_CREATION;
+    field public static final boolean DEBUG = false;
+    field public static final boolean FULL_DEBUG = false;
+    field public static long OPTIMIZED_ARRAY_ROW_CREATION;
+    field public static boolean OPTIMIZED_ENGINE;
+    field public static boolean SIMPLIFY_SYNONYMS;
+    field public static boolean SKIP_COLUMNS;
+    field public static boolean USE_BASIC_SYNONYMS;
+    field public static boolean USE_DEPENDENCY_ORDERING;
+    field public static boolean USE_SYNONYMS;
+    field public boolean graphOptimizer;
+    field public boolean hasSimpleDefinition;
+    field public boolean newgraphOptimizer;
+    field public static androidx.constraintlayout.core.Metrics! sMetrics;
+  }
+
+  public class Metrics {
+    ctor public Metrics();
+    method public void copy(androidx.constraintlayout.core.Metrics!);
+    method public void reset();
+    field public long additionalMeasures;
+    field public long bfs;
+    field public long constraints;
+    field public long determineGroups;
+    field public long errors;
+    field public long extravariables;
+    field public long fullySolved;
+    field public long graphOptimizer;
+    field public long graphSolved;
+    field public long grouping;
+    field public long infeasibleDetermineGroups;
+    field public long iterations;
+    field public long lastTableSize;
+    field public long layouts;
+    field public long linearSolved;
+    field public long mChildCount;
+    field public long mEquations;
+    field public long mMeasureCalls;
+    field public long mMeasureDuration;
+    field public int mNumberOfLayouts;
+    field public int mNumberOfMeasures;
+    field public long mSimpleEquations;
+    field public long mSolverPasses;
+    field public long mVariables;
+    field public long maxRows;
+    field public long maxTableSize;
+    field public long maxVariables;
+    field public long measuredMatchWidgets;
+    field public long measuredWidgets;
+    field public long measures;
+    field public long measuresLayoutDuration;
+    field public long measuresWidgetsDuration;
+    field public long measuresWrap;
+    field public long measuresWrapInfeasible;
+    field public long minimize;
+    field public long minimizeGoal;
+    field public long nonresolvedWidgets;
+    field public long optimize;
+    field public long pivots;
+    field public java.util.ArrayList! problematicLayouts;
+    field public long resolutions;
+    field public long resolvedWidgets;
+    field public long simpleconstraints;
+    field public long slackvariables;
+    field public long tableSizeIncrease;
+    field public long variables;
+    field public long widgets;
+  }
+
+  public class PriorityGoalRow extends androidx.constraintlayout.core.ArrayRow {
+    ctor public PriorityGoalRow(androidx.constraintlayout.core.Cache!);
+  }
+
+  public class SolverVariable implements java.lang.Comparable {
+    ctor public SolverVariable(androidx.constraintlayout.core.SolverVariable.Type!, String!);
+    ctor public SolverVariable(String!, androidx.constraintlayout.core.SolverVariable.Type!);
+    method public final void addToRow(androidx.constraintlayout.core.ArrayRow!);
+    method public int compareTo(androidx.constraintlayout.core.SolverVariable!);
+    method public String! getName();
+    method public final void removeFromRow(androidx.constraintlayout.core.ArrayRow!);
+    method public void reset();
+    method public void setFinalValue(androidx.constraintlayout.core.LinearSystem!, float);
+    method public void setName(String!);
+    method public void setSynonym(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.SolverVariable!, float);
+    method public void setType(androidx.constraintlayout.core.SolverVariable.Type!, String!);
+    method public final void updateReferencesWithNewDefinition(androidx.constraintlayout.core.LinearSystem!, androidx.constraintlayout.core.ArrayRow!);
+    field public static final int STRENGTH_BARRIER = 6; // 0x6
+    field public static final int STRENGTH_CENTERING = 7; // 0x7
+    field public static final int STRENGTH_EQUALITY = 5; // 0x5
+    field public static final int STRENGTH_FIXED = 8; // 0x8
+    field public static final int STRENGTH_HIGH = 3; // 0x3
+    field public static final int STRENGTH_HIGHEST = 4; // 0x4
+    field public static final int STRENGTH_LOW = 1; // 0x1
+    field public static final int STRENGTH_MEDIUM = 2; // 0x2
+    field public static final int STRENGTH_NONE = 0; // 0x0
+    field public float computedValue;
+    field public int id;
+    field public boolean inGoal;
+    field public boolean isFinalValue;
+    field public int strength;
+    field public int usageInRowCount;
+  }
+
+  public enum SolverVariable.Type {
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type CONSTANT;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type ERROR;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type SLACK;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type UNKNOWN;
+    enum_constant public static final androidx.constraintlayout.core.SolverVariable.Type UNRESTRICTED;
+  }
+
+  public class SolverVariableValues implements androidx.constraintlayout.core.ArrayRow.ArrayRowVariables {
+    method public void add(androidx.constraintlayout.core.SolverVariable!, float, boolean);
+    method public void clear();
+    method public boolean contains(androidx.constraintlayout.core.SolverVariable!);
+    method public void display();
+    method public void divideByAmount(float);
+    method public float get(androidx.constraintlayout.core.SolverVariable!);
+    method public int getCurrentSize();
+    method public androidx.constraintlayout.core.SolverVariable! getVariable(int);
+    method public float getVariableValue(int);
+    method public int indexOf(androidx.constraintlayout.core.SolverVariable!);
+    method public void invert();
+    method public void put(androidx.constraintlayout.core.SolverVariable!, float);
+    method public float remove(androidx.constraintlayout.core.SolverVariable!, boolean);
+    method public int sizeInBytes();
+    method public float use(androidx.constraintlayout.core.ArrayRow!, boolean);
+    field protected final androidx.constraintlayout.core.Cache! mCache;
+  }
+
+}
+
+package androidx.constraintlayout.core.dsl {
+
+  public class Barrier extends androidx.constraintlayout.core.dsl.Helper {
+    ctor public Barrier(String!);
+    ctor public Barrier(String!, String!);
+    method public androidx.constraintlayout.core.dsl.Barrier! addReference(androidx.constraintlayout.core.dsl.Ref!);
+    method public androidx.constraintlayout.core.dsl.Barrier! addReference(String!);
+    method public androidx.constraintlayout.core.dsl.Constraint.Side! getDirection();
+    method public int getMargin();
+    method public String! referencesToString();
+    method public void setDirection(androidx.constraintlayout.core.dsl.Constraint.Side!);
+    method public void setMargin(int);
+  }
+
+  public abstract class Chain extends androidx.constraintlayout.core.dsl.Helper {
+    ctor public Chain(String!);
+    method public androidx.constraintlayout.core.dsl.Chain! addReference(androidx.constraintlayout.core.dsl.Ref!);
+    method public androidx.constraintlayout.core.dsl.Chain! addReference(String!);
+    method public androidx.constraintlayout.core.dsl.Chain.Style! getStyle();
+    method public String! referencesToString();
+    method public void setStyle(androidx.constraintlayout.core.dsl.Chain.Style!);
+    field protected java.util.ArrayList! references;
+    field protected static final java.util.Map! styleMap;
+  }
+
+  public class Chain.Anchor {
+    method public void build(StringBuilder!);
+    method public String! getId();
+  }
+
+  public enum Chain.Style {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style PACKED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Chain.Style SPREAD_INSIDE;
+  }
+
+  public class Constraint {
+    ctor public Constraint(String!);
+    method protected void append(StringBuilder!, String!, float);
+    method public String! convertStringArrayToString(String![]!);
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getBaseline();
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getBottom();
+    method public float getCircleAngle();
+    method public String! getCircleConstraint();
+    method public int getCircleRadius();
+    method public String! getDimensionRatio();
+    method public int getEditorAbsoluteX();
+    method public int getEditorAbsoluteY();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getEnd();
+    method public int getHeight();
+    method public androidx.constraintlayout.core.dsl.Constraint.Behaviour! getHeightDefault();
+    method public int getHeightMax();
+    method public int getHeightMin();
+    method public float getHeightPercent();
+    method public float getHorizontalBias();
+    method public androidx.constraintlayout.core.dsl.Constraint.ChainMode! getHorizontalChainStyle();
+    method public float getHorizontalWeight();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getLeft();
+    method public String![]! getReferenceIds();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getRight();
+    method public androidx.constraintlayout.core.dsl.Constraint.HAnchor! getStart();
+    method public androidx.constraintlayout.core.dsl.Constraint.VAnchor! getTop();
+    method public float getVerticalBias();
+    method public androidx.constraintlayout.core.dsl.Constraint.ChainMode! getVerticalChainStyle();
+    method public float getVerticalWeight();
+    method public int getWidth();
+    method public androidx.constraintlayout.core.dsl.Constraint.Behaviour! getWidthDefault();
+    method public int getWidthMax();
+    method public int getWidthMin();
+    method public float getWidthPercent();
+    method public boolean isConstrainedHeight();
+    method public boolean isConstrainedWidth();
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void setCircleAngle(float);
+    method public void setCircleConstraint(String!);
+    method public void setCircleRadius(int);
+    method public void setConstrainedHeight(boolean);
+    method public void setConstrainedWidth(boolean);
+    method public void setDimensionRatio(String!);
+    method public void setEditorAbsoluteX(int);
+    method public void setEditorAbsoluteY(int);
+    method public void setHeight(int);
+    method public void setHeightDefault(androidx.constraintlayout.core.dsl.Constraint.Behaviour!);
+    method public void setHeightMax(int);
+    method public void setHeightMin(int);
+    method public void setHeightPercent(float);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalChainStyle(androidx.constraintlayout.core.dsl.Constraint.ChainMode!);
+    method public void setHorizontalWeight(float);
+    method public void setReferenceIds(String![]!);
+    method public void setVerticalBias(float);
+    method public void setVerticalChainStyle(androidx.constraintlayout.core.dsl.Constraint.ChainMode!);
+    method public void setVerticalWeight(float);
+    method public void setWidth(int);
+    method public void setWidthDefault(androidx.constraintlayout.core.dsl.Constraint.Behaviour!);
+    method public void setWidthMax(int);
+    method public void setWidthMin(int);
+    method public void setWidthPercent(float);
+    field public static final androidx.constraintlayout.core.dsl.Constraint! PARENT;
+  }
+
+  public class Constraint.Anchor {
+    method public void build(StringBuilder!);
+    method public String! getId();
+  }
+
+  public enum Constraint.Behaviour {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour PERCENT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour RATIO;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour RESOLVED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Behaviour WRAP;
+  }
+
+  public enum Constraint.ChainMode {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode PACKED;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.ChainMode SPREAD_INSIDE;
+  }
+
+  public class Constraint.HAnchor extends androidx.constraintlayout.core.dsl.Constraint.Anchor {
+  }
+
+  public enum Constraint.HSide {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.HSide START;
+  }
+
+  public enum Constraint.Side {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.Side TOP;
+  }
+
+  public class Constraint.VAnchor extends androidx.constraintlayout.core.dsl.Constraint.Anchor {
+  }
+
+  public enum Constraint.VSide {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Constraint.VSide TOP;
+  }
+
+  public class ConstraintSet {
+    ctor public ConstraintSet(String!);
+    method public void add(androidx.constraintlayout.core.dsl.Constraint!);
+    method public void add(androidx.constraintlayout.core.dsl.Helper!);
+  }
+
+  public abstract class Guideline extends androidx.constraintlayout.core.dsl.Helper {
+    method public int getEnd();
+    method public float getPercent();
+    method public int getStart();
+    method public void setEnd(int);
+    method public void setPercent(float);
+    method public void setStart(int);
+  }
+
+  public class HChain extends androidx.constraintlayout.core.dsl.Chain {
+    ctor public HChain(String!);
+    ctor public HChain(String!, String!);
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getEnd();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getLeft();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getRight();
+    method public androidx.constraintlayout.core.dsl.HChain.HAnchor! getStart();
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToEnd(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToLeft(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToRight(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int);
+    method public void linkToStart(androidx.constraintlayout.core.dsl.Constraint.HAnchor!, int, int);
+  }
+
+  public class HChain.HAnchor extends androidx.constraintlayout.core.dsl.Chain.Anchor {
+  }
+
+  public class Helper {
+    ctor public Helper(String!, androidx.constraintlayout.core.dsl.Helper.HelperType!);
+    ctor public Helper(String!, androidx.constraintlayout.core.dsl.Helper.HelperType!, String!);
+    method public void append(java.util.Map!, StringBuilder!);
+    method public java.util.Map! convertConfigToMap();
+    method public String! getConfig();
+    method public String! getId();
+    method public androidx.constraintlayout.core.dsl.Helper.HelperType! getType();
+    method public static void main(String![]!);
+    field protected String! config;
+    field protected java.util.Map! configMap;
+    field protected final String! name;
+    field protected static final java.util.Map! sideMap;
+    field protected androidx.constraintlayout.core.dsl.Helper.HelperType! type;
+    field protected static final java.util.Map! typeMap;
+  }
+
+  public static final class Helper.HelperType {
+    ctor public Helper.HelperType(String!);
+  }
+
+  public enum Helper.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type BARRIER;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type HORIZONTAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type HORIZONTAL_GUIDELINE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type VERTICAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.Helper.Type VERTICAL_GUIDELINE;
+  }
+
+  public class KeyAttribute extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyAttribute(int, String!);
+    method protected void attributesToString(StringBuilder!);
+    method public float getAlpha();
+    method public androidx.constraintlayout.core.dsl.KeyAttribute.Fit! getCurveFit();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public String! getTarget();
+    method public String! getTransitionEasing();
+    method public float getTransitionPathRotate();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public androidx.constraintlayout.core.dsl.KeyAttribute.Visibility! getVisibility();
+    method public void setAlpha(float);
+    method public void setCurveFit(androidx.constraintlayout.core.dsl.KeyAttribute.Fit!);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotation(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTarget(String!);
+    method public void setTransitionEasing(String!);
+    method public void setTransitionPathRotate(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public void setVisibility(androidx.constraintlayout.core.dsl.KeyAttribute.Visibility!);
+    field protected String! TYPE;
+  }
+
+  public enum KeyAttribute.Fit {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Fit LINEAR;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Fit SPLINE;
+  }
+
+  public enum KeyAttribute.Visibility {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility GONE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility INVISIBLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttribute.Visibility VISIBLE;
+  }
+
+  public class KeyAttributes extends androidx.constraintlayout.core.dsl.Keys {
+    method protected void attributesToString(StringBuilder!);
+    method public float[]! getAlpha();
+    method public androidx.constraintlayout.core.dsl.KeyAttributes.Fit! getCurveFit();
+    method public float[]! getPivotX();
+    method public float[]! getPivotY();
+    method public float[]! getRotation();
+    method public float[]! getRotationX();
+    method public float[]! getRotationY();
+    method public float[]! getScaleX();
+    method public float[]! getScaleY();
+    method public String![]! getTarget();
+    method public String! getTransitionEasing();
+    method public float[]! getTransitionPathRotate();
+    method public float[]! getTranslationX();
+    method public float[]! getTranslationY();
+    method public float[]! getTranslationZ();
+    method public androidx.constraintlayout.core.dsl.KeyAttributes.Visibility![]! getVisibility();
+    method public void setAlpha(float...!);
+    method public void setCurveFit(androidx.constraintlayout.core.dsl.KeyAttributes.Fit!);
+    method public void setPivotX(float...!);
+    method public void setPivotY(float...!);
+    method public void setRotation(float...!);
+    method public void setRotationX(float...!);
+    method public void setRotationY(float...!);
+    method public void setScaleX(float[]!);
+    method public void setScaleY(float[]!);
+    method public void setTarget(String![]!);
+    method public void setTransitionEasing(String!);
+    method public void setTransitionPathRotate(float...!);
+    method public void setTranslationX(float[]!);
+    method public void setTranslationY(float[]!);
+    method public void setTranslationZ(float[]!);
+    method public void setVisibility(androidx.constraintlayout.core.dsl.KeyAttributes.Visibility!...!);
+    field protected String! TYPE;
+  }
+
+  public enum KeyAttributes.Fit {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Fit LINEAR;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Fit SPLINE;
+  }
+
+  public enum KeyAttributes.Visibility {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility GONE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility INVISIBLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyAttributes.Visibility VISIBLE;
+  }
+
+  public class KeyCycle extends androidx.constraintlayout.core.dsl.KeyAttribute {
+    method public float getOffset();
+    method public float getPeriod();
+    method public float getPhase();
+    method public androidx.constraintlayout.core.dsl.KeyCycle.Wave! getShape();
+    method public void setOffset(float);
+    method public void setPeriod(float);
+    method public void setPhase(float);
+    method public void setShape(androidx.constraintlayout.core.dsl.KeyCycle.Wave!);
+  }
+
+  public enum KeyCycle.Wave {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave COS;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave REVERSE_SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave SQUARE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycle.Wave TRIANGLE;
+  }
+
+  public class KeyCycles extends androidx.constraintlayout.core.dsl.KeyAttributes {
+    method public float[]! getWaveOffset();
+    method public float[]! getWavePeriod();
+    method public float[]! getWavePhase();
+    method public androidx.constraintlayout.core.dsl.KeyCycles.Wave! getWaveShape();
+    method public void setWaveOffset(float...!);
+    method public void setWavePeriod(float...!);
+    method public void setWavePhase(float...!);
+    method public void setWaveShape(androidx.constraintlayout.core.dsl.KeyCycles.Wave!);
+  }
+
+  public enum KeyCycles.Wave {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave COS;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave REVERSE_SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SAW;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SIN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave SQUARE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyCycles.Wave TRIANGLE;
+  }
+
+  public class KeyFrames {
+    ctor public KeyFrames();
+    method public void add(androidx.constraintlayout.core.dsl.Keys!);
+  }
+
+  public class KeyPosition extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyPosition(String!, int);
+    method public int getFrames();
+    method public float getPercentHeight();
+    method public float getPercentWidth();
+    method public float getPercentX();
+    method public float getPercentY();
+    method public androidx.constraintlayout.core.dsl.KeyPosition.Type! getPositionType();
+    method public String! getTarget();
+    method public String! getTransitionEasing();
+    method public void setFrames(int);
+    method public void setPercentHeight(float);
+    method public void setPercentWidth(float);
+    method public void setPercentX(float);
+    method public void setPercentY(float);
+    method public void setPositionType(androidx.constraintlayout.core.dsl.KeyPosition.Type!);
+    method public void setTarget(String!);
+    method public void setTransitionEasing(String!);
+  }
+
+  public enum KeyPosition.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type CARTESIAN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type PATH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPosition.Type SCREEN;
+  }
+
+  public class KeyPositions extends androidx.constraintlayout.core.dsl.Keys {
+    ctor public KeyPositions(int, java.lang.String!...!);
+    method public int[]! getFrames();
+    method public float[]! getPercentHeight();
+    method public float[]! getPercentWidth();
+    method public float[]! getPercentX();
+    method public float[]! getPercentY();
+    method public androidx.constraintlayout.core.dsl.KeyPositions.Type! getPositionType();
+    method public String![]! getTarget();
+    method public String! getTransitionEasing();
+    method public void setFrames(int...!);
+    method public void setPercentHeight(float...!);
+    method public void setPercentWidth(float...!);
+    method public void setPercentX(float...!);
+    method public void setPercentY(float...!);
+    method public void setPositionType(androidx.constraintlayout.core.dsl.KeyPositions.Type!);
+    method public void setTransitionEasing(String!);
+  }
+
+  public enum KeyPositions.Type {
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type CARTESIAN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type PATH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.KeyPositions.Type SCREEN;
+  }
+
+  public class Keys {
+    ctor public Keys();
+    method protected void append(StringBuilder!, String!, float);
+    method protected void append(StringBuilder!, String!, float[]!);
+    method protected void append(StringBuilder!, String!, int);
+    method protected void append(StringBuilder!, String!, String!);
+    method protected void append(StringBuilder!, String!, String![]!);
+    method protected String! unpack(String![]!);
+  }
+
+  public class MotionScene {
+    ctor public MotionScene();
+    method public void addConstraintSet(androidx.constraintlayout.core.dsl.ConstraintSet!);
+    method public void addTransition(androidx.constraintlayout.core.dsl.Transition!);
+  }
+
+  public class OnSwipe {
+    ctor public OnSwipe();
+    ctor public OnSwipe(String!, androidx.constraintlayout.core.dsl.OnSwipe.Side!, androidx.constraintlayout.core.dsl.OnSwipe.Drag!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Mode! getAutoCompleteMode();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Drag! getDragDirection();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public String! getLimitBoundsTo();
+    method public float getMaxAcceleration();
+    method public float getMaxVelocity();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.TouchUp! getOnTouchUp();
+    method public String! getRotationCenterId();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Boundary! getSpringBoundary();
+    method public float getSpringDamping();
+    method public float getSpringMass();
+    method public float getSpringStiffness();
+    method public float getSpringStopThreshold();
+    method public String! getTouchAnchorId();
+    method public androidx.constraintlayout.core.dsl.OnSwipe.Side! getTouchAnchorSide();
+    method public void setAutoCompleteMode(androidx.constraintlayout.core.dsl.OnSwipe.Mode!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragDirection(androidx.constraintlayout.core.dsl.OnSwipe.Drag!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragScale(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setDragThreshold(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setLimitBoundsTo(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setMaxAcceleration(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setMaxVelocity(int);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setOnTouchUp(androidx.constraintlayout.core.dsl.OnSwipe.TouchUp!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setRotateCenter(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringBoundary(androidx.constraintlayout.core.dsl.OnSwipe.Boundary!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringDamping(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringMass(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringStiffness(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setSpringStopThreshold(float);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setTouchAnchorId(String!);
+    method public androidx.constraintlayout.core.dsl.OnSwipe! setTouchAnchorSide(androidx.constraintlayout.core.dsl.OnSwipe.Side!);
+    field public static final int FLAG_DISABLE_POST_SCROLL = 1; // 0x1
+    field public static final int FLAG_DISABLE_SCROLL = 2; // 0x2
+  }
+
+  public enum OnSwipe.Boundary {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_BOTH;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary BOUNCE_START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Boundary OVERSHOOT;
+  }
+
+  public enum OnSwipe.Drag {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag ANTICLOCKWISE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag CLOCKWISE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag DOWN;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Drag UP;
+  }
+
+  public enum OnSwipe.Mode {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Mode SPRING;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Mode VELOCITY;
+  }
+
+  public enum OnSwipe.Side {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side LEFT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side MIDDLE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.Side TOP;
+  }
+
+  public enum OnSwipe.TouchUp {
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp AUTOCOMPLETE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp DECELERATE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp DECELERATE_COMPLETE;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp NEVER_COMPLETE_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp NEVER_COMPLETE_START;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp STOP;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp TO_END;
+    enum_constant public static final androidx.constraintlayout.core.dsl.OnSwipe.TouchUp TO_START;
+  }
+
+  public class Ref {
+    method public static void addStringToReferences(String!, java.util.ArrayList!);
+    method public String! getId();
+    method public float getPostMargin();
+    method public float getPreMargin();
+    method public float getWeight();
+    method public static float parseFloat(Object!);
+    method public static androidx.constraintlayout.core.dsl.Ref! parseStringToRef(String!);
+    method public void setId(String!);
+    method public void setPostMargin(float);
+    method public void setPreMargin(float);
+    method public void setWeight(float);
+  }
+
+  public class Transition {
+    ctor public Transition(String!, String!);
+    ctor public Transition(String!, String!, String!);
+    method public String! getId();
+    method public void setDuration(int);
+    method public void setFrom(String!);
+    method public void setId(String!);
+    method public void setKeyFrames(androidx.constraintlayout.core.dsl.Keys!);
+    method public void setOnSwipe(androidx.constraintlayout.core.dsl.OnSwipe!);
+    method public void setStagger(float);
+    method public void setTo(String!);
+  }
+
+  public class VChain extends androidx.constraintlayout.core.dsl.Chain {
+    ctor public VChain(String!);
+    ctor public VChain(String!, String!);
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getBaseline();
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getBottom();
+    method public androidx.constraintlayout.core.dsl.VChain.VAnchor! getTop();
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBaseline(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToBottom(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int);
+    method public void linkToTop(androidx.constraintlayout.core.dsl.Constraint.VAnchor!, int, int);
+  }
+
+  public class VChain.VAnchor extends androidx.constraintlayout.core.dsl.Chain.Anchor {
+  }
+
+  public class VGuideline extends androidx.constraintlayout.core.dsl.Guideline {
+    ctor public VGuideline(String!);
+    ctor public VGuideline(String!, String!);
+  }
+
+}
+
+package androidx.constraintlayout.core.motion {
+
+  public class CustomAttribute {
+    ctor public CustomAttribute(androidx.constraintlayout.core.motion.CustomAttribute!, Object!);
+    ctor public CustomAttribute(String!, androidx.constraintlayout.core.motion.CustomAttribute.AttributeType!);
+    ctor public CustomAttribute(String!, androidx.constraintlayout.core.motion.CustomAttribute.AttributeType!, Object!, boolean);
+    method public boolean diff(androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public androidx.constraintlayout.core.motion.CustomAttribute.AttributeType! getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public static int hsvToRgb(float, float, float);
+    method public boolean isContinuous();
+    method public int numberOfInterpolatedValues();
+    method public void setColorValue(int);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public enum CustomAttribute.AttributeType {
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType BOOLEAN_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType COLOR_DRAWABLE_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType COLOR_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType DIMENSION_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType FLOAT_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType INT_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType REFERENCE_TYPE;
+    enum_constant public static final androidx.constraintlayout.core.motion.CustomAttribute.AttributeType STRING_TYPE;
+  }
+
+  public class CustomVariable {
+    ctor public CustomVariable(androidx.constraintlayout.core.motion.CustomVariable!);
+    ctor public CustomVariable(androidx.constraintlayout.core.motion.CustomVariable!, Object!);
+    ctor public CustomVariable(String!, int);
+    ctor public CustomVariable(String!, int, boolean);
+    ctor public CustomVariable(String!, int, float);
+    ctor public CustomVariable(String!, int, int);
+    ctor public CustomVariable(String!, int, Object!);
+    ctor public CustomVariable(String!, int, String!);
+    method public void applyToWidget(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public static String! colorString(int);
+    method public androidx.constraintlayout.core.motion.CustomVariable! copy();
+    method public boolean diff(androidx.constraintlayout.core.motion.CustomVariable!);
+    method public boolean getBooleanValue();
+    method public int getColorValue();
+    method public float getFloatValue();
+    method public int getIntegerValue();
+    method public int getInterpolatedColor(float[]!);
+    method public String! getName();
+    method public String! getStringValue();
+    method public int getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public static int hsvToRgb(float, float, float);
+    method public boolean isContinuous();
+    method public int numberOfInterpolatedValues();
+    method public static int rgbaTocColor(float, float, float, float);
+    method public void setBooleanValue(boolean);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setInterpolatedValue(androidx.constraintlayout.core.motion.MotionWidget!, float[]!);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public class Motion implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public Motion(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void addKey(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public int buildKeyFrames(float[]!, int[]!, int[]!);
+    method public void buildPath(float[]!, int);
+    method public void buildRect(float, float[]!, int);
+    method public String! getAnimateRelativeTo();
+    method public void getCenter(double, float[]!, float[]!);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public void getDpDt(float, float, float, float[]!);
+    method public int getDrawPath();
+    method public float getFinalHeight();
+    method public float getFinalWidth();
+    method public float getFinalX();
+    method public float getFinalY();
+    method public int getId(String!);
+    method public androidx.constraintlayout.core.motion.MotionPaths! getKeyFrame(int);
+    method public int getKeyFrameInfo(int, int[]!);
+    method public int getKeyFramePositions(int[]!, float[]!);
+    method public float getMotionStagger();
+    method public float getStartHeight();
+    method public float getStartWidth();
+    method public float getStartX();
+    method public float getStartY();
+    method public int getTransformPivotTarget();
+    method public androidx.constraintlayout.core.motion.MotionWidget! getView();
+    method public boolean interpolate(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+    method public void setDrawPath(int);
+    method public void setEnd(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setIdString(String!);
+    method public void setPathMotionArc(int);
+    method public void setStaggerOffset(float);
+    method public void setStaggerScale(float);
+    method public void setStart(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setStartState(androidx.constraintlayout.core.motion.utils.ViewState!, androidx.constraintlayout.core.motion.MotionWidget!, int, int, int);
+    method public void setTransformPivotTarget(int);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public void setView(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public void setup(int, int, float, long);
+    method public void setupRelative(androidx.constraintlayout.core.motion.Motion!);
+    field public static final int DRAW_PATH_AS_CONFIGURED = 4; // 0x4
+    field public static final int DRAW_PATH_BASIC = 1; // 0x1
+    field public static final int DRAW_PATH_CARTESIAN = 3; // 0x3
+    field public static final int DRAW_PATH_NONE = 0; // 0x0
+    field public static final int DRAW_PATH_RECTANGLE = 5; // 0x5
+    field public static final int DRAW_PATH_RELATIVE = 2; // 0x2
+    field public static final int DRAW_PATH_SCREEN = 6; // 0x6
+    field public static final int HORIZONTAL_PATH_X = 2; // 0x2
+    field public static final int HORIZONTAL_PATH_Y = 3; // 0x3
+    field public static final int PATH_PERCENT = 0; // 0x0
+    field public static final int PATH_PERPENDICULAR = 1; // 0x1
+    field public static final int ROTATION_LEFT = 2; // 0x2
+    field public static final int ROTATION_RIGHT = 1; // 0x1
+    field public static final int VERTICAL_PATH_X = 4; // 0x4
+    field public static final int VERTICAL_PATH_Y = 5; // 0x5
+    field public String! mId;
+  }
+
+  public class MotionPaths implements java.lang.Comparable {
+    ctor public MotionPaths();
+    ctor public MotionPaths(int, int, androidx.constraintlayout.core.motion.key.MotionKeyPosition!, androidx.constraintlayout.core.motion.MotionPaths!, androidx.constraintlayout.core.motion.MotionPaths!);
+    method public void applyParameters(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public int compareTo(androidx.constraintlayout.core.motion.MotionPaths!);
+    method public void configureRelativeTo(androidx.constraintlayout.core.motion.Motion!);
+    method public void setupRelative(androidx.constraintlayout.core.motion.Motion!, androidx.constraintlayout.core.motion.MotionPaths!);
+    field public static final int CARTESIAN = 0; // 0x0
+    field public static final boolean DEBUG = false;
+    field public static final boolean OLD_WAY = false;
+    field public static final int PERPENDICULAR = 1; // 0x1
+    field public static final int SCREEN = 2; // 0x2
+    field public static final String TAG = "MotionPaths";
+    field public String! mId;
+  }
+
+  public class MotionWidget implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public MotionWidget();
+    ctor public MotionWidget(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public androidx.constraintlayout.core.motion.MotionWidget! findViewById(int);
+    method public float getAlpha();
+    method public int getBottom();
+    method public androidx.constraintlayout.core.motion.CustomVariable! getCustomAttribute(String!);
+    method public java.util.Set! getCustomAttributeNames();
+    method public int getHeight();
+    method public int getId(String!);
+    method public int getLeft();
+    method public String! getName();
+    method public androidx.constraintlayout.core.motion.MotionWidget! getParent();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public int getRight();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getTop();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public float getValueAttributes(int);
+    method public int getVisibility();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getWidgetFrame();
+    method public int getWidth();
+    method public int getX();
+    method public int getY();
+    method public void layout(int, int, int, int);
+    method public void setBounds(int, int, int, int);
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setInterpolatedValue(androidx.constraintlayout.core.motion.CustomAttribute!, float[]!);
+    method public void setPivotX(float);
+    method public void setPivotY(float);
+    method public void setRotationX(float);
+    method public void setRotationY(float);
+    method public void setRotationZ(float);
+    method public void setScaleX(float);
+    method public void setScaleY(float);
+    method public void setTranslationX(float);
+    method public void setTranslationY(float);
+    method public void setTranslationZ(float);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public boolean setValueAttributes(int, float);
+    method public boolean setValueMotion(int, float);
+    method public boolean setValueMotion(int, int);
+    method public boolean setValueMotion(int, String!);
+    method public void setVisibility(int);
+    method public void updateMotion(androidx.constraintlayout.core.motion.utils.TypedValues!);
+    field public static final int FILL_PARENT = -1; // 0xffffffff
+    field public static final int GONE_UNSET = -2147483648; // 0x80000000
+    field public static final int INVISIBLE = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VISIBILITY_MODE_IGNORE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_NORMAL = 0; // 0x0
+    field public static final int VISIBLE = 4; // 0x4
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public static class MotionWidget.Motion {
+    ctor public MotionWidget.Motion();
+    field public int mAnimateCircleAngleTo;
+    field public String! mAnimateRelativeTo;
+    field public int mDrawPath;
+    field public float mMotionStagger;
+    field public int mPathMotionArc;
+    field public float mPathRotate;
+    field public int mPolarRelativeTo;
+    field public int mQuantizeInterpolatorID;
+    field public String! mQuantizeInterpolatorString;
+    field public int mQuantizeInterpolatorType;
+    field public float mQuantizeMotionPhase;
+    field public int mQuantizeMotionSteps;
+    field public String! mTransitionEasing;
+  }
+
+  public static class MotionWidget.PropertySet {
+    ctor public MotionWidget.PropertySet();
+    field public float alpha;
+    field public float mProgress;
+    field public int mVisibilityMode;
+    field public int visibility;
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.key {
+
+  public class MotionConstraintSet {
+    ctor public MotionConstraintSet();
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public String! mIdString;
+    field public int mRotate;
+  }
+
+  public abstract class MotionKey implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public MotionKey();
+    method public abstract void addValues(java.util.HashMap!);
+    method public abstract androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public androidx.constraintlayout.core.motion.key.MotionKey! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public abstract void getAttributeNames(java.util.HashSet!);
+    method public int getFramePosition();
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setFramePosition(int);
+    method public void setInterpolation(java.util.HashMap!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! setViewId(int);
+    field public static final String ALPHA = "alpha";
+    field public static final String CUSTOM = "CUSTOM";
+    field public static final String ELEVATION = "elevation";
+    field public static final String ROTATION = "rotationZ";
+    field public static final String ROTATION_X = "rotationX";
+    field public static final String SCALE_X = "scaleX";
+    field public static final String SCALE_Y = "scaleY";
+    field public static final String TRANSITION_PATH_ROTATE = "transitionPathRotate";
+    field public static final String TRANSLATION_X = "translationX";
+    field public static final String TRANSLATION_Y = "translationY";
+    field public static int UNSET;
+    field public static final String VISIBILITY = "visibility";
+    field public java.util.HashMap! mCustom;
+    field public int mFramePosition;
+    field public int mType;
+  }
+
+  public class MotionKeyAttributes extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyAttributes();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getCurveFit();
+    method public int getId(String!);
+    method public void printAttributes();
+    field public static final int KEY_TYPE = 1; // 0x1
+  }
+
+  public class MotionKeyCycle extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyCycle();
+    method public void addCycleValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void dump();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    method public float getValue(String!);
+    method public void printAttributes();
+    field public static final int KEY_TYPE = 4; // 0x4
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class MotionKeyPosition extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyPosition();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    method public boolean intersects(int, int, androidx.constraintlayout.core.motion.utils.FloatRect!, androidx.constraintlayout.core.motion.utils.FloatRect!, float, float);
+    method public void positionAttributes(androidx.constraintlayout.core.motion.MotionWidget!, androidx.constraintlayout.core.motion.utils.FloatRect!, androidx.constraintlayout.core.motion.utils.FloatRect!, float, float, String![]!, float[]!);
+    field protected static final float SELECTION_SLOPE = 20.0f;
+    field public static final int TYPE_CARTESIAN = 0; // 0x0
+    field public static final int TYPE_PATH = 1; // 0x1
+    field public static final int TYPE_SCREEN = 2; // 0x2
+    field public float mAltPercentX;
+    field public float mAltPercentY;
+    field public int mCurveFit;
+    field public int mDrawPath;
+    field public int mPathMotionArc;
+    field public float mPercentHeight;
+    field public float mPercentWidth;
+    field public float mPercentX;
+    field public float mPercentY;
+    field public int mPositionType;
+    field public String! mTransitionEasing;
+  }
+
+  public class MotionKeyTimeCycle extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyTimeCycle();
+    method public void addTimeValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public androidx.constraintlayout.core.motion.key.MotionKeyTimeCycle! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    field public static final int KEY_TYPE = 3; // 0x3
+  }
+
+  public class MotionKeyTrigger extends androidx.constraintlayout.core.motion.key.MotionKey {
+    ctor public MotionKeyTrigger();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.core.motion.key.MotionKey! clone();
+    method public void conditionallyFire(float, androidx.constraintlayout.core.motion.MotionWidget!);
+    method public androidx.constraintlayout.core.motion.key.MotionKeyTrigger! copy(androidx.constraintlayout.core.motion.key.MotionKey!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public int getId(String!);
+    field public static final String CROSS = "CROSS";
+    field public static final int KEY_TYPE = 5; // 0x5
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final int TYPE_CROSS = 312; // 0x138
+    field public static final int TYPE_NEGATIVE_CROSS = 310; // 0x136
+    field public static final int TYPE_POSITIVE_CROSS = 309; // 0x135
+    field public static final int TYPE_POST_LAYOUT = 304; // 0x130
+    field public static final int TYPE_TRIGGER_COLLISION_ID = 307; // 0x133
+    field public static final int TYPE_TRIGGER_COLLISION_VIEW = 306; // 0x132
+    field public static final int TYPE_TRIGGER_ID = 308; // 0x134
+    field public static final int TYPE_TRIGGER_RECEIVER = 311; // 0x137
+    field public static final int TYPE_TRIGGER_SLACK = 305; // 0x131
+    field public static final int TYPE_VIEW_TRANSITION_ON_CROSS = 301; // 0x12d
+    field public static final int TYPE_VIEW_TRANSITION_ON_NEGATIVE_CROSS = 303; // 0x12f
+    field public static final int TYPE_VIEW_TRANSITION_ON_POSITIVE_CROSS = 302; // 0x12e
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.parse {
+
+  public class KeyParser {
+    ctor public KeyParser();
+    method public static void main(String![]!);
+    method public static androidx.constraintlayout.core.motion.utils.TypedBundle! parseAttributes(String!);
+  }
+
+}
+
+package androidx.constraintlayout.core.motion.utils {
+
+  public class ArcCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public ArcCurveFit(int[]!, double[]!, double[]![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+    field public static final int ARC_ABOVE = 5; // 0x5
+    field public static final int ARC_BELOW = 4; // 0x4
+    field public static final int ARC_START_FLIP = 3; // 0x3
+    field public static final int ARC_START_HORIZONTAL = 2; // 0x2
+    field public static final int ARC_START_LINEAR = 0; // 0x0
+    field public static final int ARC_START_VERTICAL = 1; // 0x1
+  }
+
+  public abstract class CurveFit {
+    ctor public CurveFit();
+    method public static androidx.constraintlayout.core.motion.utils.CurveFit! get(int, double[]!, double[]![]!);
+    method public static androidx.constraintlayout.core.motion.utils.CurveFit! getArc(int[]!, double[]!, double[]![]!);
+    method public abstract void getPos(double, double[]!);
+    method public abstract void getPos(double, float[]!);
+    method public abstract double getPos(double, int);
+    method public abstract void getSlope(double, double[]!);
+    method public abstract double getSlope(double, int);
+    method public abstract double[]! getTimePoints();
+    field public static final int CONSTANT = 2; // 0x2
+    field public static final int LINEAR = 1; // 0x1
+    field public static final int SPLINE = 0; // 0x0
+  }
+
+  public interface DifferentialInterpolator {
+    method public float getInterpolation(float);
+    method public float getVelocity();
+  }
+
+  public class Easing {
+    ctor public Easing();
+    method public double get(double);
+    method public double getDiff(double);
+    method public static androidx.constraintlayout.core.motion.utils.Easing! getInterpolator(String!);
+    field public static String![]! NAMED_EASING;
+  }
+
+  public class FloatRect {
+    ctor public FloatRect();
+    method public final float centerX();
+    method public final float centerY();
+    field public float bottom;
+    field public float left;
+    field public float right;
+    field public float top;
+  }
+
+  public class HyperSpline {
+    ctor public HyperSpline();
+    ctor public HyperSpline(double[]![]!);
+    method public double approxLength(androidx.constraintlayout.core.motion.utils.HyperSpline.Cubic![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getVelocity(double, double[]!);
+    method public void setup(double[]![]!);
+  }
+
+  public static class HyperSpline.Cubic {
+    ctor public HyperSpline.Cubic(double, double, double, double);
+    method public double eval(double);
+    method public double vel(double);
+  }
+
+  public class KeyCache {
+    ctor public KeyCache();
+    method public float getFloatValue(Object!, String!, int);
+    method public void setFloatValue(Object!, String!, int, float);
+  }
+
+  public abstract class KeyCycleOscillator {
+    ctor public KeyCycleOscillator();
+    method public float get(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public float getSlope(float);
+    method public static androidx.constraintlayout.core.motion.utils.KeyCycleOscillator! makeWidgetCycle(String!);
+    method protected void setCustom(Object!);
+    method public void setPoint(int, int, String!, int, float, float, float, float);
+    method public void setPoint(int, int, String!, int, float, float, float, float, Object!);
+    method public void setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float);
+    method public void setType(String!);
+    method public void setup(float);
+    method public boolean variesByPath();
+    field public int mVariesBy;
+  }
+
+  public static class KeyCycleOscillator.PathRotateSet extends androidx.constraintlayout.core.motion.utils.KeyCycleOscillator {
+    ctor public KeyCycleOscillator.PathRotateSet(String!);
+    method public void setPathRotate(androidx.constraintlayout.core.motion.MotionWidget!, float, double, double);
+  }
+
+  public class KeyFrameArray {
+    ctor public KeyFrameArray();
+  }
+
+  public static class KeyFrameArray.CustomArray {
+    ctor public KeyFrameArray.CustomArray();
+    method public void append(int, androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public void clear();
+    method public void dump();
+    method public int keyAt(int);
+    method public void remove(int);
+    method public int size();
+    method public androidx.constraintlayout.core.motion.CustomAttribute! valueAt(int);
+  }
+
+  public static class KeyFrameArray.CustomVar {
+    ctor public KeyFrameArray.CustomVar();
+    method public void append(int, androidx.constraintlayout.core.motion.CustomVariable!);
+    method public void clear();
+    method public void dump();
+    method public int keyAt(int);
+    method public void remove(int);
+    method public int size();
+    method public androidx.constraintlayout.core.motion.CustomVariable! valueAt(int);
+  }
+
+  public class LinearCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public LinearCurveFit(double[]!, double[]![]!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+  }
+
+  public class MonotonicCurveFit extends androidx.constraintlayout.core.motion.utils.CurveFit {
+    ctor public MonotonicCurveFit(double[]!, double[]![]!);
+    method public static androidx.constraintlayout.core.motion.utils.MonotonicCurveFit! buildWave(String!);
+    method public void getPos(double, double[]!);
+    method public void getPos(double, float[]!);
+    method public double getPos(double, int);
+    method public void getSlope(double, double[]!);
+    method public double getSlope(double, int);
+    method public double[]! getTimePoints();
+  }
+
+  public class Oscillator {
+    ctor public Oscillator();
+    method public void addPoint(double, float);
+    method public double getSlope(double, double, double);
+    method public double getValue(double, double);
+    method public void normalize();
+    method public void setType(int, String!);
+    field public static final int BOUNCE = 6; // 0x6
+    field public static final int COS_WAVE = 5; // 0x5
+    field public static final int CUSTOM = 7; // 0x7
+    field public static final int REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SAW_WAVE = 3; // 0x3
+    field public static final int SIN_WAVE = 0; // 0x0
+    field public static final int SQUARE_WAVE = 1; // 0x1
+    field public static String! TAG;
+    field public static final int TRIANGLE_WAVE = 2; // 0x2
+  }
+
+  public class Rect {
+    ctor public Rect();
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public class Schlick extends androidx.constraintlayout.core.motion.utils.Easing {
+  }
+
+  public abstract class SplineSet {
+    ctor public SplineSet();
+    method public float get(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public float getSlope(float);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeCustomSpline(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeCustomSplineSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public static androidx.constraintlayout.core.motion.utils.SplineSet! makeSpline(String!, long);
+    method public void setPoint(int, float);
+    method public void setProperty(androidx.constraintlayout.core.motion.utils.TypedValues!, float);
+    method public void setType(String!);
+    method public void setup(int);
+    field protected androidx.constraintlayout.core.motion.utils.CurveFit! mCurveFit;
+    field protected int[]! mTimePoints;
+    field protected float[]! mValues;
+  }
+
+  public static class SplineSet.CustomSet extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public SplineSet.CustomSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomAttribute!);
+    method public void setProperty(androidx.constraintlayout.core.state.WidgetFrame!, float);
+  }
+
+  public static class SplineSet.CustomSpline extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public SplineSet.CustomSpline(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomVariable!);
+    method public void setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float);
+  }
+
+  public class SpringStopEngine implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public SpringStopEngine();
+    method public String! debug(String!, float);
+    method public float getAcceleration();
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+    method public void springConfig(float, float, float, float, float, float, float, int);
+  }
+
+  public class StepCurve extends androidx.constraintlayout.core.motion.utils.Easing {
+  }
+
+  public interface StopEngine {
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public class StopLogicEngine implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public StopLogicEngine();
+    method public void config(float, float, float, float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public static class StopLogicEngine.Decelerate implements androidx.constraintlayout.core.motion.utils.StopEngine {
+    ctor public StopLogicEngine.Decelerate();
+    method public void config(float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+  }
+
+  public abstract class TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet();
+    method protected float calcWave(float);
+    method public androidx.constraintlayout.core.motion.utils.CurveFit! getCurveFit();
+    method public void setPoint(int, float, float, int, float);
+    method protected void setStartTime(long);
+    method public void setType(String!);
+    method public void setup(int);
+    field protected static final int CURVE_OFFSET = 2; // 0x2
+    field protected static final int CURVE_PERIOD = 1; // 0x1
+    field protected static final int CURVE_VALUE = 0; // 0x0
+    field protected float[]! mCache;
+    field protected boolean mContinue;
+    field protected int mCount;
+    field protected androidx.constraintlayout.core.motion.utils.CurveFit! mCurveFit;
+    field protected float mLastCycle;
+    field protected long mLastTime;
+    field protected int[]! mTimePoints;
+    field protected String! mType;
+    field protected float[]![]! mValues;
+    field protected int mWaveShape;
+    field protected static float sVal2PI;
+  }
+
+  public static class TimeCycleSplineSet.CustomSet extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet.CustomSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomArray!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomAttribute!, float, int, float);
+    method public boolean setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class TimeCycleSplineSet.CustomVarSet extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public TimeCycleSplineSet.CustomVarSet(String!, androidx.constraintlayout.core.motion.utils.KeyFrameArray.CustomVar!);
+    method public void setPoint(int, androidx.constraintlayout.core.motion.CustomVariable!, float, int, float);
+    method public boolean setProperty(androidx.constraintlayout.core.motion.MotionWidget!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  protected static class TimeCycleSplineSet.Sort {
+    ctor protected TimeCycleSplineSet.Sort();
+  }
+
+  public class TypedBundle {
+    ctor public TypedBundle();
+    method public void add(int, boolean);
+    method public void add(int, float);
+    method public void add(int, int);
+    method public void add(int, String!);
+    method public void addIfNotNull(int, String!);
+    method public void applyDelta(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void applyDelta(androidx.constraintlayout.core.motion.utils.TypedValues!);
+    method public void clear();
+    method public int getInteger(int);
+  }
+
+  public interface TypedValues {
+    method public int getId(String!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    field public static final int BOOLEAN_MASK = 1; // 0x1
+    field public static final int FLOAT_MASK = 4; // 0x4
+    field public static final int INT_MASK = 2; // 0x2
+    field public static final int STRING_MASK = 8; // 0x8
+    field public static final String S_CUSTOM = "CUSTOM";
+    field public static final int TYPE_FRAME_POSITION = 100; // 0x64
+    field public static final int TYPE_TARGET = 101; // 0x65
+  }
+
+  public static interface TypedValues.AttributesType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyAttributes";
+    field public static final String S_ALPHA = "alpha";
+    field public static final String S_CURVE_FIT = "curveFit";
+    field public static final String S_CUSTOM = "CUSTOM";
+    field public static final String S_EASING = "easing";
+    field public static final String S_ELEVATION = "elevation";
+    field public static final String S_FRAME = "frame";
+    field public static final String S_PATH_ROTATE = "pathRotate";
+    field public static final String S_PIVOT_TARGET = "pivotTarget";
+    field public static final String S_PIVOT_X = "pivotX";
+    field public static final String S_PIVOT_Y = "pivotY";
+    field public static final String S_PROGRESS = "progress";
+    field public static final String S_ROTATION_X = "rotationX";
+    field public static final String S_ROTATION_Y = "rotationY";
+    field public static final String S_ROTATION_Z = "rotationZ";
+    field public static final String S_SCALE_X = "scaleX";
+    field public static final String S_SCALE_Y = "scaleY";
+    field public static final String S_TARGET = "target";
+    field public static final String S_TRANSLATION_X = "translationX";
+    field public static final String S_TRANSLATION_Y = "translationY";
+    field public static final String S_TRANSLATION_Z = "translationZ";
+    field public static final String S_VISIBILITY = "visibility";
+    field public static final int TYPE_ALPHA = 303; // 0x12f
+    field public static final int TYPE_CURVE_FIT = 301; // 0x12d
+    field public static final int TYPE_EASING = 317; // 0x13d
+    field public static final int TYPE_ELEVATION = 307; // 0x133
+    field public static final int TYPE_PATH_ROTATE = 316; // 0x13c
+    field public static final int TYPE_PIVOT_TARGET = 318; // 0x13e
+    field public static final int TYPE_PIVOT_X = 313; // 0x139
+    field public static final int TYPE_PIVOT_Y = 314; // 0x13a
+    field public static final int TYPE_PROGRESS = 315; // 0x13b
+    field public static final int TYPE_ROTATION_X = 308; // 0x134
+    field public static final int TYPE_ROTATION_Y = 309; // 0x135
+    field public static final int TYPE_ROTATION_Z = 310; // 0x136
+    field public static final int TYPE_SCALE_X = 311; // 0x137
+    field public static final int TYPE_SCALE_Y = 312; // 0x138
+    field public static final int TYPE_TRANSLATION_X = 304; // 0x130
+    field public static final int TYPE_TRANSLATION_Y = 305; // 0x131
+    field public static final int TYPE_TRANSLATION_Z = 306; // 0x132
+    field public static final int TYPE_VISIBILITY = 302; // 0x12e
+  }
+
+  public static interface TypedValues.Custom {
+    method public static int getId(String!);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Custom";
+    field public static final String S_BOOLEAN = "boolean";
+    field public static final String S_COLOR = "color";
+    field public static final String S_DIMENSION = "dimension";
+    field public static final String S_FLOAT = "float";
+    field public static final String S_INT = "integer";
+    field public static final String S_REFERENCE = "reference";
+    field public static final String S_STRING = "string";
+    field public static final int TYPE_BOOLEAN = 904; // 0x388
+    field public static final int TYPE_COLOR = 902; // 0x386
+    field public static final int TYPE_DIMENSION = 905; // 0x389
+    field public static final int TYPE_FLOAT = 901; // 0x385
+    field public static final int TYPE_INT = 900; // 0x384
+    field public static final int TYPE_REFERENCE = 906; // 0x38a
+    field public static final int TYPE_STRING = 903; // 0x387
+  }
+
+  public static interface TypedValues.CycleType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyCycle";
+    field public static final String S_ALPHA = "alpha";
+    field public static final String S_CURVE_FIT = "curveFit";
+    field public static final String S_CUSTOM_WAVE_SHAPE = "customWave";
+    field public static final String S_EASING = "easing";
+    field public static final String S_ELEVATION = "elevation";
+    field public static final String S_PATH_ROTATE = "pathRotate";
+    field public static final String S_PIVOT_X = "pivotX";
+    field public static final String S_PIVOT_Y = "pivotY";
+    field public static final String S_PROGRESS = "progress";
+    field public static final String S_ROTATION_X = "rotationX";
+    field public static final String S_ROTATION_Y = "rotationY";
+    field public static final String S_ROTATION_Z = "rotationZ";
+    field public static final String S_SCALE_X = "scaleX";
+    field public static final String S_SCALE_Y = "scaleY";
+    field public static final String S_TRANSLATION_X = "translationX";
+    field public static final String S_TRANSLATION_Y = "translationY";
+    field public static final String S_TRANSLATION_Z = "translationZ";
+    field public static final String S_VISIBILITY = "visibility";
+    field public static final String S_WAVE_OFFSET = "offset";
+    field public static final String S_WAVE_PERIOD = "period";
+    field public static final String S_WAVE_PHASE = "phase";
+    field public static final String S_WAVE_SHAPE = "waveShape";
+    field public static final int TYPE_ALPHA = 403; // 0x193
+    field public static final int TYPE_CURVE_FIT = 401; // 0x191
+    field public static final int TYPE_CUSTOM_WAVE_SHAPE = 422; // 0x1a6
+    field public static final int TYPE_EASING = 420; // 0x1a4
+    field public static final int TYPE_ELEVATION = 307; // 0x133
+    field public static final int TYPE_PATH_ROTATE = 416; // 0x1a0
+    field public static final int TYPE_PIVOT_X = 313; // 0x139
+    field public static final int TYPE_PIVOT_Y = 314; // 0x13a
+    field public static final int TYPE_PROGRESS = 315; // 0x13b
+    field public static final int TYPE_ROTATION_X = 308; // 0x134
+    field public static final int TYPE_ROTATION_Y = 309; // 0x135
+    field public static final int TYPE_ROTATION_Z = 310; // 0x136
+    field public static final int TYPE_SCALE_X = 311; // 0x137
+    field public static final int TYPE_SCALE_Y = 312; // 0x138
+    field public static final int TYPE_TRANSLATION_X = 304; // 0x130
+    field public static final int TYPE_TRANSLATION_Y = 305; // 0x131
+    field public static final int TYPE_TRANSLATION_Z = 306; // 0x132
+    field public static final int TYPE_VISIBILITY = 402; // 0x192
+    field public static final int TYPE_WAVE_OFFSET = 424; // 0x1a8
+    field public static final int TYPE_WAVE_PERIOD = 423; // 0x1a7
+    field public static final int TYPE_WAVE_PHASE = 425; // 0x1a9
+    field public static final int TYPE_WAVE_SHAPE = 421; // 0x1a5
+  }
+
+  public static interface TypedValues.MotionScene {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "MotionScene";
+    field public static final String S_DEFAULT_DURATION = "defaultDuration";
+    field public static final String S_LAYOUT_DURING_TRANSITION = "layoutDuringTransition";
+    field public static final int TYPE_DEFAULT_DURATION = 600; // 0x258
+    field public static final int TYPE_LAYOUT_DURING_TRANSITION = 601; // 0x259
+  }
+
+  public static interface TypedValues.MotionType {
+    method public static int getId(String!);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Motion";
+    field public static final String S_ANIMATE_CIRCLEANGLE_TO = "AnimateCircleAngleTo";
+    field public static final String S_ANIMATE_RELATIVE_TO = "AnimateRelativeTo";
+    field public static final String S_DRAW_PATH = "DrawPath";
+    field public static final String S_EASING = "TransitionEasing";
+    field public static final String S_PATHMOTION_ARC = "PathMotionArc";
+    field public static final String S_PATH_ROTATE = "PathRotate";
+    field public static final String S_POLAR_RELATIVETO = "PolarRelativeTo";
+    field public static final String S_QUANTIZE_INTERPOLATOR = "QuantizeInterpolator";
+    field public static final String S_QUANTIZE_INTERPOLATOR_ID = "QuantizeInterpolatorID";
+    field public static final String S_QUANTIZE_INTERPOLATOR_TYPE = "QuantizeInterpolatorType";
+    field public static final String S_QUANTIZE_MOTIONSTEPS = "QuantizeMotionSteps";
+    field public static final String S_QUANTIZE_MOTION_PHASE = "QuantizeMotionPhase";
+    field public static final String S_STAGGER = "Stagger";
+    field public static final int TYPE_ANIMATE_CIRCLEANGLE_TO = 606; // 0x25e
+    field public static final int TYPE_ANIMATE_RELATIVE_TO = 605; // 0x25d
+    field public static final int TYPE_DRAW_PATH = 608; // 0x260
+    field public static final int TYPE_EASING = 603; // 0x25b
+    field public static final int TYPE_PATHMOTION_ARC = 607; // 0x25f
+    field public static final int TYPE_PATH_ROTATE = 601; // 0x259
+    field public static final int TYPE_POLAR_RELATIVETO = 609; // 0x261
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR = 604; // 0x25c
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR_ID = 612; // 0x264
+    field public static final int TYPE_QUANTIZE_INTERPOLATOR_TYPE = 611; // 0x263
+    field public static final int TYPE_QUANTIZE_MOTIONSTEPS = 610; // 0x262
+    field public static final int TYPE_QUANTIZE_MOTION_PHASE = 602; // 0x25a
+    field public static final int TYPE_STAGGER = 600; // 0x258
+  }
+
+  public static interface TypedValues.OnSwipe {
+    field public static final String AUTOCOMPLETE_MODE = "autocompletemode";
+    field public static final String![]! AUTOCOMPLETE_MODE_ENUM;
+    field public static final String DRAG_DIRECTION = "dragdirection";
+    field public static final String DRAG_SCALE = "dragscale";
+    field public static final String DRAG_THRESHOLD = "dragthreshold";
+    field public static final String LIMIT_BOUNDS_TO = "limitboundsto";
+    field public static final String MAX_ACCELERATION = "maxacceleration";
+    field public static final String MAX_VELOCITY = "maxvelocity";
+    field public static final String MOVE_WHEN_SCROLLAT_TOP = "movewhenscrollattop";
+    field public static final String NESTED_SCROLL_FLAGS = "nestedscrollflags";
+    field public static final String![]! NESTED_SCROLL_FLAGS_ENUM;
+    field public static final String ON_TOUCH_UP = "ontouchup";
+    field public static final String![]! ON_TOUCH_UP_ENUM;
+    field public static final String ROTATION_CENTER_ID = "rotationcenterid";
+    field public static final String SPRINGS_TOP_THRESHOLD = "springstopthreshold";
+    field public static final String SPRING_BOUNDARY = "springboundary";
+    field public static final String![]! SPRING_BOUNDARY_ENUM;
+    field public static final String SPRING_DAMPING = "springdamping";
+    field public static final String SPRING_MASS = "springmass";
+    field public static final String SPRING_STIFFNESS = "springstiffness";
+    field public static final String TOUCH_ANCHOR_ID = "touchanchorid";
+    field public static final String TOUCH_ANCHOR_SIDE = "touchanchorside";
+    field public static final String TOUCH_REGION_ID = "touchregionid";
+  }
+
+  public static interface TypedValues.PositionType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyPosition";
+    field public static final String S_DRAWPATH = "drawPath";
+    field public static final String S_PERCENT_HEIGHT = "percentHeight";
+    field public static final String S_PERCENT_WIDTH = "percentWidth";
+    field public static final String S_PERCENT_X = "percentX";
+    field public static final String S_PERCENT_Y = "percentY";
+    field public static final String S_SIZE_PERCENT = "sizePercent";
+    field public static final String S_TRANSITION_EASING = "transitionEasing";
+    field public static final int TYPE_CURVE_FIT = 508; // 0x1fc
+    field public static final int TYPE_DRAWPATH = 502; // 0x1f6
+    field public static final int TYPE_PATH_MOTION_ARC = 509; // 0x1fd
+    field public static final int TYPE_PERCENT_HEIGHT = 504; // 0x1f8
+    field public static final int TYPE_PERCENT_WIDTH = 503; // 0x1f7
+    field public static final int TYPE_PERCENT_X = 506; // 0x1fa
+    field public static final int TYPE_PERCENT_Y = 507; // 0x1fb
+    field public static final int TYPE_POSITION_TYPE = 510; // 0x1fe
+    field public static final int TYPE_SIZE_PERCENT = 505; // 0x1f9
+    field public static final int TYPE_TRANSITION_EASING = 501; // 0x1f5
+  }
+
+  public static interface TypedValues.TransitionType {
+    method public static int getId(String!);
+    method public static int getType(int);
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "Transitions";
+    field public static final String S_AUTO_TRANSITION = "autoTransition";
+    field public static final String S_DURATION = "duration";
+    field public static final String S_FROM = "from";
+    field public static final String S_INTERPOLATOR = "motionInterpolator";
+    field public static final String S_PATH_MOTION_ARC = "pathMotionArc";
+    field public static final String S_STAGGERED = "staggered";
+    field public static final String S_TO = "to";
+    field public static final String S_TRANSITION_FLAGS = "transitionFlags";
+    field public static final int TYPE_AUTO_TRANSITION = 704; // 0x2c0
+    field public static final int TYPE_DURATION = 700; // 0x2bc
+    field public static final int TYPE_FROM = 701; // 0x2bd
+    field public static final int TYPE_INTERPOLATOR = 705; // 0x2c1
+    field public static final int TYPE_PATH_MOTION_ARC = 509; // 0x1fd
+    field public static final int TYPE_STAGGERED = 706; // 0x2c2
+    field public static final int TYPE_TO = 702; // 0x2be
+    field public static final int TYPE_TRANSITION_FLAGS = 707; // 0x2c3
+  }
+
+  public static interface TypedValues.TriggerType {
+    method public static int getId(String!);
+    field public static final String CROSS = "CROSS";
+    field public static final String![]! KEY_WORDS;
+    field public static final String NAME = "KeyTrigger";
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final int TYPE_CROSS = 312; // 0x138
+    field public static final int TYPE_NEGATIVE_CROSS = 310; // 0x136
+    field public static final int TYPE_POSITIVE_CROSS = 309; // 0x135
+    field public static final int TYPE_POST_LAYOUT = 304; // 0x130
+    field public static final int TYPE_TRIGGER_COLLISION_ID = 307; // 0x133
+    field public static final int TYPE_TRIGGER_COLLISION_VIEW = 306; // 0x132
+    field public static final int TYPE_TRIGGER_ID = 308; // 0x134
+    field public static final int TYPE_TRIGGER_RECEIVER = 311; // 0x137
+    field public static final int TYPE_TRIGGER_SLACK = 305; // 0x131
+    field public static final int TYPE_VIEW_TRANSITION_ON_CROSS = 301; // 0x12d
+    field public static final int TYPE_VIEW_TRANSITION_ON_NEGATIVE_CROSS = 303; // 0x12f
+    field public static final int TYPE_VIEW_TRANSITION_ON_POSITIVE_CROSS = 302; // 0x12e
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+  public class Utils {
+    ctor public Utils();
+    method public int getInterpolatedColor(float[]!);
+    method public static void log(String!);
+    method public static void log(String!, String!);
+    method public static void logStack(String!, int);
+    method public static void loge(String!, String!);
+    method public static int rgbaTocColor(float, float, float, float);
+    method public static void setDebugHandle(androidx.constraintlayout.core.motion.utils.Utils.DebugHandle!);
+    method public static void socketSend(String!);
+  }
+
+  public static interface Utils.DebugHandle {
+    method public void message(String!);
+  }
+
+  public class VelocityMatrix {
+    ctor public VelocityMatrix();
+    method public void applyTransform(float, float, int, int, float[]!);
+    method public void clear();
+    method public void setRotationVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setRotationVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+    method public void setScaleVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setScaleVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+    method public void setTranslationVelocity(androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, androidx.constraintlayout.core.motion.utils.KeyCycleOscillator!, float);
+    method public void setTranslationVelocity(androidx.constraintlayout.core.motion.utils.SplineSet!, androidx.constraintlayout.core.motion.utils.SplineSet!, float);
+  }
+
+  public class ViewState {
+    ctor public ViewState();
+    method public void getState(androidx.constraintlayout.core.motion.MotionWidget!);
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public float rotation;
+    field public int top;
+  }
+
+}
+
+package androidx.constraintlayout.core.parser {
+
+  public class CLArray extends androidx.constraintlayout.core.parser.CLContainer {
+    ctor public CLArray(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+  }
+
+  public class CLContainer extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLContainer(char[]!);
+    method public void add(androidx.constraintlayout.core.parser.CLElement!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public void clear();
+    method public androidx.constraintlayout.core.parser.CLContainer clone();
+    method public androidx.constraintlayout.core.parser.CLElement! get(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLElement! get(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArray(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArray(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLArray! getArrayOrCreate(String!);
+    method public androidx.constraintlayout.core.parser.CLArray! getArrayOrNull(String!);
+    method public boolean getBoolean(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public boolean getBoolean(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloat(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloat(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public float getFloatOrNaN(String!);
+    method public int getInt(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public int getInt(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObject(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObject(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLObject! getObjectOrNull(String!);
+    method public androidx.constraintlayout.core.parser.CLElement! getOrNull(int);
+    method public androidx.constraintlayout.core.parser.CLElement! getOrNull(String!);
+    method public String! getString(int) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public String! getString(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public String! getStringOrNull(int);
+    method public String! getStringOrNull(String!);
+    method public boolean has(String!);
+    method public java.util.ArrayList! names();
+    method public void put(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public void putNumber(String!, float);
+    method public void putString(String!, String!);
+    method public void remove(String!);
+    method public int size();
+  }
+
+  public class CLElement implements java.lang.Cloneable {
+    ctor public CLElement(char[]!);
+    method protected void addIndent(StringBuilder!, int);
+    method public androidx.constraintlayout.core.parser.CLElement clone();
+    method public String! content();
+    method public androidx.constraintlayout.core.parser.CLElement! getContainer();
+    method protected String! getDebugName();
+    method public long getEnd();
+    method public float getFloat();
+    method public int getInt();
+    method public int getLine();
+    method public long getStart();
+    method protected String! getStrClass();
+    method public boolean hasContent();
+    method public boolean isDone();
+    method public boolean isStarted();
+    method public boolean notStarted();
+    method public void setContainer(androidx.constraintlayout.core.parser.CLContainer!);
+    method public void setEnd(long);
+    method public void setLine(int);
+    method public void setStart(long);
+    method protected String! toFormattedJSON(int, int);
+    method protected String! toJSON();
+    field protected androidx.constraintlayout.core.parser.CLContainer! mContainer;
+    field protected long mEnd;
+    field protected long mStart;
+    field protected static int sBaseIndent;
+    field protected static int sMaxLine;
+  }
+
+  public class CLKey extends androidx.constraintlayout.core.parser.CLContainer {
+    ctor public CLKey(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public String! getName();
+    method public androidx.constraintlayout.core.parser.CLElement! getValue();
+    method public void set(androidx.constraintlayout.core.parser.CLElement!);
+  }
+
+  public class CLNumber extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLNumber(char[]!);
+    ctor public CLNumber(float);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public boolean isInt();
+    method public void putValue(float);
+  }
+
+  public class CLObject extends androidx.constraintlayout.core.parser.CLContainer implements java.lang.Iterable {
+    ctor public CLObject(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLObject! allocate(char[]!);
+    method public androidx.constraintlayout.core.parser.CLObject clone();
+    method public java.util.Iterator! iterator();
+    method public String! toFormattedJSON();
+    method public String! toFormattedJSON(int, int);
+    method public String! toJSON();
+  }
+
+  public class CLParser {
+    ctor public CLParser(String!);
+    method public androidx.constraintlayout.core.parser.CLObject! parse() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static androidx.constraintlayout.core.parser.CLObject! parse(String!) throws androidx.constraintlayout.core.parser.CLParsingException;
+  }
+
+  public class CLParsingException extends java.lang.Exception {
+    ctor public CLParsingException(String!, androidx.constraintlayout.core.parser.CLElement!);
+    method public String! reason();
+  }
+
+  public class CLString extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLString(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLString from(String);
+  }
+
+  public class CLToken extends androidx.constraintlayout.core.parser.CLElement {
+    ctor public CLToken(char[]!);
+    method public static androidx.constraintlayout.core.parser.CLElement! allocate(char[]!);
+    method public boolean getBoolean() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.parser.CLToken.Type! getType();
+    method public boolean isNull() throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public boolean validate(char, long);
+  }
+
+}
+
+package androidx.constraintlayout.core.state {
+
+  public class ConstraintReference implements androidx.constraintlayout.core.state.Reference {
+    ctor public ConstraintReference(androidx.constraintlayout.core.state.State!);
+    method public void addCustomColor(String!, int);
+    method public void addCustomFloat(String!, float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! alpha(float);
+    method public void apply();
+    method public void applyWidgetConstraints();
+    method public androidx.constraintlayout.core.state.ConstraintReference! baseline();
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToBaseline(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! baselineToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottom();
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottomToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! bottomToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! centerHorizontally(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! centerVertically(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! circularConstraint(Object!, float, float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! clear();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearAll();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearHorizontal();
+    method public androidx.constraintlayout.core.state.ConstraintReference! clearVertical();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! createConstraintWidget();
+    method public androidx.constraintlayout.core.state.ConstraintReference! end();
+    method public androidx.constraintlayout.core.state.ConstraintReference! endToEnd(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! endToStart(Object!);
+    method public float getAlpha();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public androidx.constraintlayout.core.state.Dimension! getHeight();
+    method public int getHorizontalChainStyle();
+    method public float getHorizontalChainWeight();
+    method public Object! getKey();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotationX();
+    method public float getRotationY();
+    method public float getRotationZ();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public String! getTag();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public float getTranslationZ();
+    method public int getVerticalChainStyle(int);
+    method public float getVerticalChainWeight();
+    method public Object! getView();
+    method public androidx.constraintlayout.core.state.Dimension! getWidth();
+    method public androidx.constraintlayout.core.state.ConstraintReference! height(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! horizontalBias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! left();
+    method public androidx.constraintlayout.core.state.ConstraintReference! leftToLeft(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! leftToRight(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! margin(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! margin(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! marginGone(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! marginGone(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! pivotX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! pivotY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! right();
+    method public androidx.constraintlayout.core.state.ConstraintReference! rightToLeft(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rightToRight(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! rotationZ(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! scaleX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! scaleY(float);
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setFacade(androidx.constraintlayout.core.state.helpers.Facade!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! setHeight(androidx.constraintlayout.core.state.Dimension!);
+    method public void setHorizontalChainStyle(int);
+    method public void setHorizontalChainWeight(float);
+    method public void setKey(Object!);
+    method public void setTag(String!);
+    method public void setVerticalChainStyle(int);
+    method public void setVerticalChainWeight(float);
+    method public void setView(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! setWidth(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! start();
+    method public androidx.constraintlayout.core.state.ConstraintReference! startToEnd(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! startToStart(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! top();
+    method public androidx.constraintlayout.core.state.ConstraintReference! topToBottom(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! topToTop(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationX(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationY(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! translationZ(float);
+    method public void validate() throws java.lang.Exception;
+    method public androidx.constraintlayout.core.state.ConstraintReference! verticalBias(float);
+    method public androidx.constraintlayout.core.state.ConstraintReference! visibility(int);
+    method public androidx.constraintlayout.core.state.ConstraintReference! width(androidx.constraintlayout.core.state.Dimension!);
+    field protected Object! mBottomToBottom;
+    field protected Object! mBottomToTop;
+    field protected Object! mEndToEnd;
+    field protected Object! mEndToStart;
+    field protected float mHorizontalBias;
+    field protected Object! mLeftToLeft;
+    field protected Object! mLeftToRight;
+    field protected int mMarginBottom;
+    field protected int mMarginBottomGone;
+    field protected int mMarginEnd;
+    field protected int mMarginEndGone;
+    field protected int mMarginLeft;
+    field protected int mMarginLeftGone;
+    field protected int mMarginRight;
+    field protected int mMarginRightGone;
+    field protected int mMarginStart;
+    field protected int mMarginStartGone;
+    field protected int mMarginTop;
+    field protected int mMarginTopGone;
+    field protected Object! mRightToLeft;
+    field protected Object! mRightToRight;
+    field protected Object! mStartToEnd;
+    field protected Object! mStartToStart;
+    field protected Object! mTopToBottom;
+    field protected Object! mTopToTop;
+    field protected float mVerticalBias;
+  }
+
+  public static interface ConstraintReference.ConstraintReferenceFactory {
+    method public androidx.constraintlayout.core.state.ConstraintReference! create(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class ConstraintSetParser {
+    ctor public ConstraintSetParser();
+    method public static void parseDesignElementsJSON(String!, java.util.ArrayList!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseJSON(String!, androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.ConstraintSetParser.LayoutVariables!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseJSON(String!, androidx.constraintlayout.core.state.Transition!, int);
+    method public static void parseMotionSceneJSON(androidx.constraintlayout.core.state.CoreMotionScene!, String!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void populateState(androidx.constraintlayout.core.parser.CLObject, androidx.constraintlayout.core.state.State, androidx.constraintlayout.core.state.ConstraintSetParser.LayoutVariables) throws androidx.constraintlayout.core.parser.CLParsingException;
+  }
+
+  public static class ConstraintSetParser.DesignElement {
+    method public String! getId();
+    method public java.util.HashMap! getParams();
+    method public String! getType();
+  }
+
+  public static class ConstraintSetParser.LayoutVariables {
+    ctor public ConstraintSetParser.LayoutVariables();
+    method public void putOverride(String!, float);
+  }
+
+  public enum ConstraintSetParser.MotionLayoutDebugFlags {
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags NONE;
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags SHOW_ALL;
+    enum_constant public static final androidx.constraintlayout.core.state.ConstraintSetParser.MotionLayoutDebugFlags UNKNOWN;
+  }
+
+  public interface CoreMotionScene {
+    method public String! getConstraintSet(int);
+    method public String! getConstraintSet(String!);
+    method public String! getTransition(String!);
+    method public void setConstraintSetContent(String!, String!);
+    method public void setDebugName(String!);
+    method public void setTransitionContent(String!, String!);
+  }
+
+  public interface CorePixelDp {
+    method public float toPixels(float);
+  }
+
+  public class Dimension {
+    method public void apply(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public static androidx.constraintlayout.core.state.Dimension! createFixed(int);
+    method public static androidx.constraintlayout.core.state.Dimension! createFixed(Object!);
+    method public static androidx.constraintlayout.core.state.Dimension! createParent();
+    method public static androidx.constraintlayout.core.state.Dimension! createPercent(Object!, float);
+    method public static androidx.constraintlayout.core.state.Dimension! createRatio(String!);
+    method public static androidx.constraintlayout.core.state.Dimension! createSpread();
+    method public static androidx.constraintlayout.core.state.Dimension! createSuggested(int);
+    method public static androidx.constraintlayout.core.state.Dimension! createSuggested(Object!);
+    method public static androidx.constraintlayout.core.state.Dimension! createWrap();
+    method public boolean equalsFixedValue(int);
+    method public androidx.constraintlayout.core.state.Dimension! fixed(int);
+    method public androidx.constraintlayout.core.state.Dimension! fixed(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! max(int);
+    method public androidx.constraintlayout.core.state.Dimension! max(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! min(int);
+    method public androidx.constraintlayout.core.state.Dimension! min(Object!);
+    method public androidx.constraintlayout.core.state.Dimension! percent(Object!, float);
+    method public androidx.constraintlayout.core.state.Dimension! ratio(String!);
+    method public androidx.constraintlayout.core.state.Dimension! suggested(int);
+    method public androidx.constraintlayout.core.state.Dimension! suggested(Object!);
+    field public static final Object! FIXED_DIMENSION;
+    field public static final Object! PARENT_DIMENSION;
+    field public static final Object! PERCENT_DIMENSION;
+    field public static final Object! RATIO_DIMENSION;
+    field public static final Object! SPREAD_DIMENSION;
+    field public static final Object! WRAP_DIMENSION;
+  }
+
+  public enum Dimension.Type {
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type FIXED;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type MATCH_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type MATCH_PARENT;
+    enum_constant public static final androidx.constraintlayout.core.state.Dimension.Type WRAP;
+  }
+
+  public class HelperReference extends androidx.constraintlayout.core.state.ConstraintReference implements androidx.constraintlayout.core.state.helpers.Facade {
+    ctor public HelperReference(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.State.Helper!);
+    method public androidx.constraintlayout.core.state.HelperReference! add(java.lang.Object!...!);
+    method public void applyBase();
+    method public androidx.constraintlayout.core.widgets.HelperWidget! getHelperWidget();
+    method public androidx.constraintlayout.core.state.State.Helper! getType();
+    method public void setHelperWidget(androidx.constraintlayout.core.widgets.HelperWidget!);
+    field protected final androidx.constraintlayout.core.state.State! mHelperState;
+    field protected java.util.ArrayList! mReferences;
+  }
+
+  public interface Interpolator {
+    method public float getInterpolation(float);
+  }
+
+  public interface Reference {
+    method public void apply();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public Object! getKey();
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setKey(Object!);
+  }
+
+  public class Registry {
+    ctor public Registry();
+    method public String! currentContent(String!);
+    method public String! currentLayoutInformation(String!);
+    method public static androidx.constraintlayout.core.state.Registry! getInstance();
+    method public long getLastModified(String!);
+    method public java.util.Set! getLayoutList();
+    method public void register(String!, androidx.constraintlayout.core.state.RegistryCallback!);
+    method public void setDrawDebug(String!, int);
+    method public void setLayoutInformationMode(String!, int);
+    method public void unregister(String!, androidx.constraintlayout.core.state.RegistryCallback!);
+    method public void updateContent(String!, String!);
+    method public void updateDimensions(String!, int, int);
+    method public void updateProgress(String!, float);
+  }
+
+  public interface RegistryCallback {
+    method public String! currentLayoutInformation();
+    method public String! currentMotionScene();
+    method public long getLastModified();
+    method public void onDimensions(int, int);
+    method public void onNewMotionScene(String!);
+    method public void onProgress(float);
+    method public void setDrawDebug(int);
+    method public void setLayoutInformationMode(int);
+  }
+
+  public class State {
+    ctor public State();
+    method public void apply(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public androidx.constraintlayout.core.state.helpers.BarrierReference! barrier(Object!, androidx.constraintlayout.core.state.State.Direction!);
+    method public void baselineNeededFor(Object!);
+    method public androidx.constraintlayout.core.state.helpers.AlignHorizontallyReference! centerHorizontally(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.AlignVerticallyReference! centerVertically(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! constraints(Object!);
+    method public int convertDimension(Object!);
+    method public androidx.constraintlayout.core.state.ConstraintReference! createConstraintReference(Object!);
+    method public void directMapping();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getFlow(Object!, boolean);
+    method public androidx.constraintlayout.core.state.helpers.GridReference getGrid(Object, String);
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getHorizontalFlow();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getHorizontalFlow(java.lang.Object!...!);
+    method public java.util.ArrayList! getIdsForTag(String!);
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getVerticalFlow();
+    method public androidx.constraintlayout.core.state.helpers.FlowReference! getVerticalFlow(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! guideline(Object!, int);
+    method public androidx.constraintlayout.core.state.State! height(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.HelperReference! helper(Object!, androidx.constraintlayout.core.state.State.Helper!);
+    method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain();
+    method public androidx.constraintlayout.core.state.helpers.HorizontalChainReference! horizontalChain(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! horizontalGuideline(Object!);
+    method public boolean isBaselineNeeded(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method @Deprecated public boolean isLtr();
+    method public boolean isRtl();
+    method public void map(Object!, Object!);
+    method public void reset();
+    method public boolean sameFixedHeight(int);
+    method public boolean sameFixedWidth(int);
+    method public void setDpToPixel(androidx.constraintlayout.core.state.CorePixelDp!);
+    method public androidx.constraintlayout.core.state.State! setHeight(androidx.constraintlayout.core.state.Dimension!);
+    method @Deprecated public void setLtr(boolean);
+    method public void setRtl(boolean);
+    method public void setTag(String!, String!);
+    method public androidx.constraintlayout.core.state.State! setWidth(androidx.constraintlayout.core.state.Dimension!);
+    method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain();
+    method public androidx.constraintlayout.core.state.helpers.VerticalChainReference! verticalChain(java.lang.Object!...!);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! verticalGuideline(Object!);
+    method public androidx.constraintlayout.core.state.State! width(androidx.constraintlayout.core.state.Dimension!);
+    field public static final Integer PARENT;
+    field protected java.util.HashMap! mHelperReferences;
+    field public final androidx.constraintlayout.core.state.ConstraintReference! mParent;
+    field protected java.util.HashMap! mReferences;
+  }
+
+  public enum State.Chain {
+    method public static androidx.constraintlayout.core.state.State.Chain! getChainByString(String!);
+    method public static int getValueByString(String!);
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain PACKED;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain SPREAD;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Chain SPREAD_INSIDE;
+    field public static java.util.Map! chainMap;
+    field public static java.util.Map! valueMap;
+  }
+
+  public enum State.Constraint {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BASELINE_TO_TOP;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint BOTTOM_TO_TOP;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CENTER_HORIZONTALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CENTER_VERTICALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint CIRCULAR_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint END_TO_END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint END_TO_START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint LEFT_TO_LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint LEFT_TO_RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint RIGHT_TO_LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint RIGHT_TO_RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint START_TO_END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint START_TO_START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Constraint TOP_TO_TOP;
+  }
+
+  public enum State.Direction {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction END;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction LEFT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction START;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Direction TOP;
+  }
+
+  public enum State.Helper {
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ALIGN_HORIZONTALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ALIGN_VERTICALLY;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper BARRIER;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper COLUMN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper FLOW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper GRID;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper HORIZONTAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper HORIZONTAL_FLOW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper LAYER;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper ROW;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper VERTICAL_CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Helper VERTICAL_FLOW;
+  }
+
+  public enum State.Wrap {
+    method public static androidx.constraintlayout.core.state.State.Wrap! getChainByString(String!);
+    method public static int getValueByString(String!);
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap ALIGNED;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap CHAIN;
+    enum_constant public static final androidx.constraintlayout.core.state.State.Wrap NONE;
+    field public static java.util.Map! valueMap;
+    field public static java.util.Map! wrapMap;
+  }
+
+  public class Transition implements androidx.constraintlayout.core.motion.utils.TypedValues {
+    ctor public Transition(androidx.constraintlayout.core.state.CorePixelDp);
+    method public void addCustomColor(int, String!, String!, int);
+    method public void addCustomFloat(int, String!, String!, float);
+    method public void addKeyAttribute(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyAttribute(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!, androidx.constraintlayout.core.motion.CustomVariable![]!);
+    method public void addKeyCycle(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyPosition(String!, androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void addKeyPosition(String!, int, int, float, float);
+    method public void calcStagger();
+    method public void clear();
+    method public boolean contains(String!);
+    method public float dragToProgress(float, int, int, float, float);
+    method public void fillKeyPositions(androidx.constraintlayout.core.state.WidgetFrame!, float[]!, float[]!, float[]!);
+    method public androidx.constraintlayout.core.state.Transition.KeyPosition! findNextPosition(String!, int);
+    method public androidx.constraintlayout.core.state.Transition.KeyPosition! findPreviousPosition(String!, int);
+    method public int getAutoTransition();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getEnd(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getEnd(String!);
+    method public int getId(String!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getInterpolated(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getInterpolated(String!);
+    method public int getInterpolatedHeight();
+    method public int getInterpolatedWidth();
+    method public androidx.constraintlayout.core.state.Interpolator! getInterpolator();
+    method public static androidx.constraintlayout.core.state.Interpolator! getInterpolator(int, String!);
+    method public int getKeyFrames(String!, float[]!, int[]!, int[]!);
+    method public androidx.constraintlayout.core.motion.Motion! getMotion(String!);
+    method public int getNumberKeyPositions(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public float[]! getPath(String!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getStart(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public androidx.constraintlayout.core.state.WidgetFrame! getStart(String!);
+    method public float getTouchUpProgress(long);
+    method public androidx.constraintlayout.core.state.Transition.WidgetState! getWidgetState(String!, androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public boolean hasOnSwipe();
+    method public boolean hasPositionKeyframes();
+    method public void interpolate(int, int, float);
+    method public boolean isEmpty();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public boolean isFirstDownAccepted(float, float);
+    method public boolean isTouchNotDone(float);
+    method public void setTouchUp(float, long, float, float);
+    method public void setTransitionProperties(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public boolean setValue(int, boolean);
+    method public boolean setValue(int, float);
+    method public boolean setValue(int, int);
+    method public boolean setValue(int, String!);
+    method public void updateFrom(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int);
+    field public static final int END = 1; // 0x1
+    field public static final int INTERPOLATED = 2; // 0x2
+    field public static final int START = 0; // 0x0
+  }
+
+  public static class Transition.WidgetState {
+    ctor public Transition.WidgetState();
+    method public androidx.constraintlayout.core.state.WidgetFrame! getFrame(int);
+    method public void interpolate(int, int, float, androidx.constraintlayout.core.state.Transition!);
+    method public void setKeyAttribute(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setKeyAttribute(androidx.constraintlayout.core.motion.utils.TypedBundle!, androidx.constraintlayout.core.motion.CustomVariable![]!);
+    method public void setKeyCycle(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setKeyPosition(androidx.constraintlayout.core.motion.utils.TypedBundle!);
+    method public void setPathRelative(androidx.constraintlayout.core.state.Transition.WidgetState!);
+    method public void update(androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+  }
+
+  public class TransitionParser {
+    ctor public TransitionParser();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static void parse(androidx.constraintlayout.core.parser.CLObject, androidx.constraintlayout.core.state.Transition) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method @Deprecated public static void parse(androidx.constraintlayout.core.parser.CLObject!, androidx.constraintlayout.core.state.Transition!, androidx.constraintlayout.core.state.CorePixelDp!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public static void parseKeyFrames(androidx.constraintlayout.core.parser.CLObject!, androidx.constraintlayout.core.state.Transition!) throws androidx.constraintlayout.core.parser.CLParsingException;
+  }
+
+  public class WidgetFrame {
+    ctor public WidgetFrame();
+    ctor public WidgetFrame(androidx.constraintlayout.core.state.WidgetFrame!);
+    ctor public WidgetFrame(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void addCustomColor(String!, int);
+    method public void addCustomFloat(String!, float);
+    method public float centerX();
+    method public float centerY();
+    method public boolean containsCustom(String);
+    method public androidx.constraintlayout.core.motion.CustomVariable! getCustomAttribute(String!);
+    method public java.util.Set! getCustomAttributeNames();
+    method public int getCustomColor(String!);
+    method public float getCustomFloat(String!);
+    method public String! getId();
+    method public androidx.constraintlayout.core.motion.utils.TypedBundle! getMotionProperties();
+    method public int height();
+    method public static void interpolate(int, int, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.WidgetFrame!, androidx.constraintlayout.core.state.Transition!, float);
+    method public boolean isDefaultTransform();
+    method public StringBuilder! serialize(StringBuilder!);
+    method public StringBuilder! serialize(StringBuilder!, boolean);
+    method public void setCustomAttribute(String!, int, boolean);
+    method public void setCustomAttribute(String!, int, float);
+    method public void setCustomAttribute(String!, int, int);
+    method public void setCustomAttribute(String!, int, String!);
+    method public void setCustomValue(androidx.constraintlayout.core.motion.CustomAttribute!, float[]!);
+    method public boolean setValue(String!, androidx.constraintlayout.core.parser.CLElement!) throws androidx.constraintlayout.core.parser.CLParsingException;
+    method public androidx.constraintlayout.core.state.WidgetFrame! update();
+    method public androidx.constraintlayout.core.state.WidgetFrame! update(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void updateAttributes(androidx.constraintlayout.core.state.WidgetFrame!);
+    method public int width();
+    field public float alpha;
+    field public int bottom;
+    field public float interpolatedPos;
+    field public int left;
+    field public String! name;
+    field public static float phone_orientation;
+    field public float pivotX;
+    field public float pivotY;
+    field public int right;
+    field public float rotationX;
+    field public float rotationY;
+    field public float rotationZ;
+    field public float scaleX;
+    field public float scaleY;
+    field public int top;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+    field public int visibility;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget! widget;
+  }
+
+}
+
+package androidx.constraintlayout.core.state.helpers {
+
+  public class AlignHorizontallyReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public AlignHorizontallyReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class AlignVerticallyReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public AlignVerticallyReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class BarrierReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public BarrierReference(androidx.constraintlayout.core.state.State!);
+    method public void setBarrierDirection(androidx.constraintlayout.core.state.State.Direction!);
+  }
+
+  public class ChainReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public ChainReference(androidx.constraintlayout.core.state.State, androidx.constraintlayout.core.state.State.Helper);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addChainElement(Object, float, float, float, float, float);
+    method public void addChainElement(String, float, float, float);
+    method public androidx.constraintlayout.core.state.helpers.ChainReference bias(float);
+    method public float getBias();
+    method protected float getPostMargin(String);
+    method protected float getPreMargin(String);
+    method public androidx.constraintlayout.core.state.State.Chain getStyle();
+    method protected float getWeight(String);
+    method public androidx.constraintlayout.core.state.helpers.ChainReference style(androidx.constraintlayout.core.state.State.Chain);
+    field protected float mBias;
+    field @Deprecated protected java.util.HashMap mMapPostMargin;
+    field @Deprecated protected java.util.HashMap mMapPreMargin;
+    field @Deprecated protected java.util.HashMap mMapWeights;
+    field protected androidx.constraintlayout.core.state.State.Chain mStyle;
+  }
+
+  public interface Facade {
+    method public void apply();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+  }
+
+  public class FlowReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public FlowReference(androidx.constraintlayout.core.state.State!, androidx.constraintlayout.core.state.State.Helper!);
+    method public void addFlowElement(String!, float, float, float);
+    method public float getFirstHorizontalBias();
+    method public int getFirstHorizontalStyle();
+    method public float getFirstVerticalBias();
+    method public int getFirstVerticalStyle();
+    method public int getHorizontalAlign();
+    method public float getHorizontalBias();
+    method public int getHorizontalGap();
+    method public int getHorizontalStyle();
+    method public float getLastHorizontalBias();
+    method public int getLastHorizontalStyle();
+    method public float getLastVerticalBias();
+    method public int getLastVerticalStyle();
+    method public int getMaxElementsWrap();
+    method public int getOrientation();
+    method public int getPaddingBottom();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingTop();
+    method protected float getPostMargin(String!);
+    method protected float getPreMargin(String!);
+    method public int getVerticalAlign();
+    method public float getVerticalBias();
+    method public int getVerticalGap();
+    method public int getVerticalStyle();
+    method protected float getWeight(String!);
+    method public int getWrapMode();
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingTop(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field protected float mFirstHorizontalBias;
+    field protected int mFirstHorizontalStyle;
+    field protected float mFirstVerticalBias;
+    field protected int mFirstVerticalStyle;
+    field protected androidx.constraintlayout.core.widgets.Flow! mFlow;
+    field protected int mHorizontalAlign;
+    field protected int mHorizontalGap;
+    field protected int mHorizontalStyle;
+    field protected float mLastHorizontalBias;
+    field protected int mLastHorizontalStyle;
+    field protected float mLastVerticalBias;
+    field protected int mLastVerticalStyle;
+    field protected java.util.HashMap! mMapPostMargin;
+    field protected java.util.HashMap! mMapPreMargin;
+    field protected java.util.HashMap! mMapWeights;
+    field protected int mMaxElementsWrap;
+    field protected int mOrientation;
+    field protected int mPaddingBottom;
+    field protected int mPaddingLeft;
+    field protected int mPaddingRight;
+    field protected int mPaddingTop;
+    field protected int mVerticalAlign;
+    field protected int mVerticalGap;
+    field protected int mVerticalStyle;
+    field protected int mWrapMode;
+  }
+
+  public class GridReference extends androidx.constraintlayout.core.state.HelperReference {
+    ctor public GridReference(androidx.constraintlayout.core.state.State, androidx.constraintlayout.core.state.State.Helper);
+    method public String? getColumnWeights();
+    method public int getColumnsSet();
+    method public int getFlags();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public int getPaddingBottom();
+    method public int getPaddingEnd();
+    method public int getPaddingStart();
+    method public int getPaddingTop();
+    method public String? getRowWeights();
+    method public int getRowsSet();
+    method public String? getSkips();
+    method public String? getSpans();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String);
+    method public void setColumnsSet(int);
+    method public void setFlags(int);
+    method public void setFlags(String);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingEnd(int);
+    method public void setPaddingStart(int);
+    method public void setPaddingTop(int);
+    method public void setRowWeights(String);
+    method public void setRowsSet(int);
+    method public void setSkips(String);
+    method public void setSpans(String);
+    method public void setVerticalGaps(float);
+  }
+
+  public class GuidelineReference implements androidx.constraintlayout.core.state.helpers.Facade androidx.constraintlayout.core.state.Reference {
+    ctor public GuidelineReference(androidx.constraintlayout.core.state.State!);
+    method public void apply();
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! end(Object!);
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public androidx.constraintlayout.core.state.helpers.Facade! getFacade();
+    method public Object! getKey();
+    method public int getOrientation();
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! percent(float);
+    method public void setConstraintWidget(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setKey(Object!);
+    method public void setOrientation(int);
+    method public androidx.constraintlayout.core.state.helpers.GuidelineReference! start(Object!);
+  }
+
+  public class HorizontalChainReference extends androidx.constraintlayout.core.state.helpers.ChainReference {
+    ctor public HorizontalChainReference(androidx.constraintlayout.core.state.State!);
+  }
+
+  public class VerticalChainReference extends androidx.constraintlayout.core.state.helpers.ChainReference {
+    ctor public VerticalChainReference(androidx.constraintlayout.core.state.State!);
+  }
+
+}
+
+package androidx.constraintlayout.core.utils {
+
+  public class GridCore extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public GridCore();
+    ctor public GridCore(int, int);
+    method public String? getColumnWeights();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidgetContainer? getContainer();
+    method public int getFlags();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public String? getRowWeights();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String);
+    method public void setColumns(int);
+    method public void setContainer(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer);
+    method public void setFlags(int);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setRowWeights(String);
+    method public void setRows(int);
+    method public void setSkips(String);
+    method public void setSpans(CharSequence);
+    method public void setVerticalGaps(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int SPANS_RESPECT_WIDGET_ORDER = 2; // 0x2
+    field public static final int SUB_GRID_BY_COL_ROW = 1; // 0x1
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridEngine {
+    ctor public GridEngine();
+    ctor public GridEngine(int, int);
+    ctor public GridEngine(int, int, int);
+    method public int bottomOfWidget(int);
+    method public int leftOfWidget(int);
+    method public int rightOfWidget(int);
+    method public void setColumns(int);
+    method public void setNumWidgets(int);
+    method public void setOrientation(int);
+    method public void setRows(int);
+    method public void setSkips(String!);
+    method public void setSpans(CharSequence!);
+    method public void setup();
+    method public int topOfWidget(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+}
+
+package androidx.constraintlayout.core.widgets {
+
+  public class Barrier extends androidx.constraintlayout.core.widgets.HelperWidget {
+    ctor public Barrier();
+    ctor public Barrier(String!);
+    method public boolean allSolved();
+    method @Deprecated public boolean allowsGoneWidget();
+    method public boolean getAllowsGoneWidget();
+    method public int getBarrierType();
+    method public int getMargin();
+    method public int getOrientation();
+    method protected void markWidgets();
+    method public void setAllowsGoneWidget(boolean);
+    method public void setBarrierType(int);
+    method public void setMargin(int);
+    field public static final int BOTTOM = 3; // 0x3
+    field public static final int LEFT = 0; // 0x0
+    field public static final int RIGHT = 1; // 0x1
+    field public static final int TOP = 2; // 0x2
+  }
+
+  public class Chain {
+    ctor public Chain();
+    method public static void applyChainConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, java.util.ArrayList!, int);
+    field public static final boolean USE_CHAIN_OPTIMIZATION = false;
+  }
+
+  public class ChainHead {
+    ctor public ChainHead(androidx.constraintlayout.core.widgets.ConstraintWidget!, int, boolean);
+    method public void define();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirst();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirstMatchConstraintWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getFirstVisibleWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getHead();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLast();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLastMatchConstraintWidget();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getLastVisibleWidget();
+    method public float getTotalWeight();
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirst;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirstMatchConstraintWidget;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mFirstVisibleWidget;
+    field protected boolean mHasComplexMatchWeights;
+    field protected boolean mHasDefinedWeights;
+    field protected boolean mHasRatio;
+    field protected boolean mHasUndefinedWeights;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mHead;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLast;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLastMatchConstraintWidget;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget! mLastVisibleWidget;
+    field protected float mTotalWeight;
+    field protected java.util.ArrayList! mWeightedMatchConstraintsWidgets;
+    field protected int mWidgetsCount;
+    field protected int mWidgetsMatchCount;
+  }
+
+  public class ConstraintAnchor {
+    ctor public ConstraintAnchor(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public boolean connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public boolean connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int, int, boolean);
+    method public void copyFrom(androidx.constraintlayout.core.widgets.ConstraintAnchor!, java.util.HashMap!);
+    method public void findDependents(int, java.util.ArrayList!, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public java.util.HashSet! getDependents();
+    method public int getFinalValue();
+    method public int getMargin();
+    method public final androidx.constraintlayout.core.widgets.ConstraintAnchor! getOpposite();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getOwner();
+    method public androidx.constraintlayout.core.SolverVariable! getSolverVariable();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getTarget();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor.Type! getType();
+    method public boolean hasCenteredDependents();
+    method public boolean hasDependents();
+    method public boolean hasFinalValue();
+    method public boolean isConnected();
+    method public boolean isConnectionAllowed(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public boolean isConnectionAllowed(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isSideAnchor();
+    method public boolean isSimilarDimensionConnection(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isValidConnection(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public boolean isVerticalAnchor();
+    method public void reset();
+    method public void resetFinalResolution();
+    method public void resetSolverVariable(androidx.constraintlayout.core.Cache!);
+    method public void setFinalValue(int);
+    method public void setGoneMargin(int);
+    method public void setMargin(int);
+    field public int mMargin;
+    field public final androidx.constraintlayout.core.widgets.ConstraintWidget! mOwner;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mTarget;
+    field public final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type! mType;
+  }
+
+  public enum ConstraintAnchor.Type {
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type BASELINE;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type BOTTOM;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER_X;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type CENTER_Y;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type LEFT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type NONE;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type RIGHT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintAnchor.Type TOP;
+  }
+
+  public class ConstraintWidget {
+    ctor public ConstraintWidget();
+    ctor public ConstraintWidget(int, int);
+    ctor public ConstraintWidget(int, int, int, int);
+    ctor public ConstraintWidget(String!);
+    ctor public ConstraintWidget(String!, int, int);
+    ctor public ConstraintWidget(String!, int, int, int, int);
+    method public void addChildrenToSolverByDependency(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, java.util.HashSet!, int, boolean);
+    method public void addToSolver(androidx.constraintlayout.core.LinearSystem!, boolean);
+    method public boolean allowedInBarrier();
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public void connect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int);
+    method public void connectCircularConstraint(androidx.constraintlayout.core.widgets.ConstraintWidget!, float, int);
+    method public void copy(androidx.constraintlayout.core.widgets.ConstraintWidget!, java.util.HashMap!);
+    method public void createObjectVariables(androidx.constraintlayout.core.LinearSystem!);
+    method public void ensureMeasureRequested();
+    method public void ensureWidgetRuns();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getAnchor(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!);
+    method public java.util.ArrayList! getAnchors();
+    method public int getBaselineDistance();
+    method public float getBiasPercent(int);
+    method public int getBottom();
+    method public Object! getCompanionWidget();
+    method public int getContainerItemSkip();
+    method public String! getDebugName();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getDimensionBehaviour(int);
+    method public float getDimensionRatio();
+    method public int getDimensionRatioSide();
+    method public boolean getHasBaseline();
+    method public int getHeight();
+    method public float getHorizontalBiasPercent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getHorizontalChainControlWidget();
+    method public int getHorizontalChainStyle();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getHorizontalDimensionBehaviour();
+    method public int getHorizontalMargin();
+    method public int getLastHorizontalMeasureSpec();
+    method public int getLastVerticalMeasureSpec();
+    method public int getLeft();
+    method public int getLength(int);
+    method public int getMaxHeight();
+    method public int getMaxWidth();
+    method public int getMinHeight();
+    method public int getMinWidth();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getNextChainMember(int);
+    method public int getOptimizerWrapHeight();
+    method public int getOptimizerWrapWidth();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getParent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getPreviousChainMember(int);
+    method public int getRight();
+    method protected int getRootX();
+    method protected int getRootY();
+    method public androidx.constraintlayout.core.widgets.analyzer.WidgetRun! getRun(int);
+    method public void getSceneString(StringBuilder!);
+    method public int getTop();
+    method public String! getType();
+    method public float getVerticalBiasPercent();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getVerticalChainControlWidget();
+    method public int getVerticalChainStyle();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! getVerticalDimensionBehaviour();
+    method public int getVerticalMargin();
+    method public int getVisibility();
+    method public int getWidth();
+    method public int getWrapBehaviorInParent();
+    method public int getX();
+    method public int getY();
+    method public boolean hasBaseline();
+    method public boolean hasDanglingDimension(int);
+    method public boolean hasDependencies();
+    method public boolean hasDimensionOverride();
+    method public boolean hasResolvedTargets(int, int);
+    method public void immediateConnect(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int, int);
+    method public boolean isAnimated();
+    method public boolean isHeightWrapContent();
+    method public boolean isHorizontalSolvingPassDone();
+    method public boolean isInBarrier(int);
+    method public boolean isInHorizontalChain();
+    method public boolean isInPlaceholder();
+    method public boolean isInVerticalChain();
+    method public boolean isInVirtualLayout();
+    method public boolean isMeasureRequested();
+    method public boolean isResolvedHorizontally();
+    method public boolean isResolvedVertically();
+    method public boolean isRoot();
+    method public boolean isSpreadHeight();
+    method public boolean isSpreadWidth();
+    method public boolean isVerticalSolvingPassDone();
+    method public boolean isWidthWrapContent();
+    method public void markHorizontalSolvingPassDone();
+    method public void markVerticalSolvingPassDone();
+    method public boolean oppositeDimensionDependsOn(int);
+    method public boolean oppositeDimensionsTied();
+    method public void reset();
+    method public void resetAllConstraints();
+    method public void resetAnchor(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void resetAnchors();
+    method public void resetFinalResolution();
+    method public void resetSolverVariables(androidx.constraintlayout.core.Cache!);
+    method public void resetSolvingPassFlag();
+    method public StringBuilder! serialize(StringBuilder!);
+    method public void setAnimated(boolean);
+    method public void setBaselineDistance(int);
+    method public void setCompanionWidget(Object!);
+    method public void setContainerItemSkip(int);
+    method public void setDebugName(String!);
+    method public void setDebugSolverName(androidx.constraintlayout.core.LinearSystem!, String!);
+    method public void setDimension(int, int);
+    method public void setDimensionRatio(float, int);
+    method public void setDimensionRatio(String!);
+    method public void setFinalBaseline(int);
+    method public void setFinalFrame(int, int, int, int, int, int);
+    method public void setFinalHorizontal(int, int);
+    method public void setFinalLeft(int);
+    method public void setFinalTop(int);
+    method public void setFinalVertical(int, int);
+    method public void setFrame(int, int, int);
+    method public void setFrame(int, int, int, int);
+    method public void setGoneMargin(androidx.constraintlayout.core.widgets.ConstraintAnchor.Type!, int);
+    method public void setHasBaseline(boolean);
+    method public void setHeight(int);
+    method public void setHeightWrapContent(boolean);
+    method public void setHorizontalBiasPercent(float);
+    method public void setHorizontalChainStyle(int);
+    method public void setHorizontalDimension(int, int);
+    method public void setHorizontalDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public void setHorizontalMatchStyle(int, int, int, float);
+    method public void setHorizontalWeight(float);
+    method protected void setInBarrier(int, boolean);
+    method public void setInPlaceholder(boolean);
+    method public void setInVirtualLayout(boolean);
+    method public void setLastMeasureSpec(int, int);
+    method public void setLength(int, int);
+    method public void setMaxHeight(int);
+    method public void setMaxWidth(int);
+    method public void setMeasureRequested(boolean);
+    method public void setMinHeight(int);
+    method public void setMinWidth(int);
+    method public void setOffset(int, int);
+    method public void setOrigin(int, int);
+    method public void setParent(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void setType(String!);
+    method public void setVerticalBiasPercent(float);
+    method public void setVerticalChainStyle(int);
+    method public void setVerticalDimension(int, int);
+    method public void setVerticalDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public void setVerticalMatchStyle(int, int, int, float);
+    method public void setVerticalWeight(float);
+    method public void setVisibility(int);
+    method public void setWidth(int);
+    method public void setWidthWrapContent(boolean);
+    method public void setWrapBehaviorInParent(int);
+    method public void setX(int);
+    method public void setY(int);
+    method public void setupDimensionRatio(boolean, boolean, boolean, boolean);
+    method public void updateFromRuns(boolean, boolean);
+    method public void updateFromSolver(androidx.constraintlayout.core.LinearSystem!, boolean);
+    field public static final int ANCHOR_BASELINE = 4; // 0x4
+    field public static final int ANCHOR_BOTTOM = 3; // 0x3
+    field public static final int ANCHOR_LEFT = 0; // 0x0
+    field public static final int ANCHOR_RIGHT = 1; // 0x1
+    field public static final int ANCHOR_TOP = 2; // 0x2
+    field public static final int BOTH = 2; // 0x2
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static float DEFAULT_BIAS;
+    field protected static final int DIRECT = 2; // 0x2
+    field public static final int GONE = 8; // 0x8
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVISIBLE = 4; // 0x4
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_RATIO = 3; // 0x3
+    field public static final int MATCH_CONSTRAINT_RATIO_RESOLVED = 4; // 0x4
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field protected static final int SOLVER = 1; // 0x1
+    field public static final int UNKNOWN = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VISIBLE = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_HORIZONTAL_ONLY = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_INCLUDED = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_SKIPPED = 3; // 0x3
+    field public static final int WRAP_BEHAVIOR_VERTICAL_ONLY = 2; // 0x2
+    field public androidx.constraintlayout.core.state.WidgetFrame! frame;
+    field public androidx.constraintlayout.core.widgets.analyzer.ChainRun! horizontalChainRun;
+    field public int horizontalGroup;
+    field public boolean[]! isTerminalWidget;
+    field protected java.util.ArrayList! mAnchors;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mBaseline;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mBottom;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mCenter;
+    field public float mCircleConstraintAngle;
+    field public float mDimensionRatio;
+    field protected int mDimensionRatioSide;
+    field public int mHorizontalResolution;
+    field public androidx.constraintlayout.core.widgets.analyzer.HorizontalWidgetRun! mHorizontalRun;
+    field public boolean mIsHeightWrapContent;
+    field public boolean mIsWidthWrapContent;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mLeft;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor![]! mListAnchors;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour![]! mListDimensionBehaviors;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget![]! mListNextMatchConstraintsWidget;
+    field public int mMatchConstraintDefaultHeight;
+    field public int mMatchConstraintDefaultWidth;
+    field public int mMatchConstraintMaxHeight;
+    field public int mMatchConstraintMaxWidth;
+    field public int mMatchConstraintMinHeight;
+    field public int mMatchConstraintMinWidth;
+    field public float mMatchConstraintPercentHeight;
+    field public float mMatchConstraintPercentWidth;
+    field protected int mMinHeight;
+    field protected int mMinWidth;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget![]! mNextChainWidget;
+    field protected int mOffsetX;
+    field protected int mOffsetY;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget! mParent;
+    field public int[]! mResolvedMatchConstraintDefault;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mRight;
+    field public androidx.constraintlayout.core.widgets.ConstraintAnchor! mTop;
+    field public int mVerticalResolution;
+    field public androidx.constraintlayout.core.widgets.analyzer.VerticalWidgetRun! mVerticalRun;
+    field public float[]! mWeight;
+    field protected int mX;
+    field protected int mY;
+    field public boolean measured;
+    field public androidx.constraintlayout.core.widgets.analyzer.WidgetRun![]! run;
+    field public String! stringId;
+    field public androidx.constraintlayout.core.widgets.analyzer.ChainRun! verticalChainRun;
+    field public int verticalGroup;
+  }
+
+  public enum ConstraintWidget.DimensionBehaviour {
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour FIXED;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour MATCH_CONSTRAINT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour MATCH_PARENT;
+    enum_constant public static final androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour WRAP_CONTENT;
+  }
+
+  public class ConstraintWidgetContainer extends androidx.constraintlayout.core.widgets.WidgetContainer {
+    ctor public ConstraintWidgetContainer();
+    ctor public ConstraintWidgetContainer(int, int);
+    ctor public ConstraintWidgetContainer(int, int, int, int);
+    ctor public ConstraintWidgetContainer(String!, int, int);
+    method public boolean addChildrenToSolver(androidx.constraintlayout.core.LinearSystem!);
+    method public void addHorizontalWrapMaxVariable(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void addHorizontalWrapMinVariable(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method public void defineTerminalWidgets();
+    method public boolean directMeasure(boolean);
+    method public boolean directMeasureSetup(boolean);
+    method public boolean directMeasureWithOrientation(boolean, int);
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method public java.util.ArrayList! getHorizontalGuidelines();
+    method public androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer! getMeasurer();
+    method public int getOptimizationLevel();
+    method public androidx.constraintlayout.core.LinearSystem! getSystem();
+    method public java.util.ArrayList! getVerticalGuidelines();
+    method public boolean handlesInternalConstraints();
+    method public void invalidateGraph();
+    method public void invalidateMeasures();
+    method public boolean isHeightMeasuredTooSmall();
+    method public boolean isRtl();
+    method public boolean isWidthMeasuredTooSmall();
+    method public static boolean measure(int, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure!, int);
+    method public long measure(int, int, int, int, int, int, int, int, int);
+    method public boolean optimizeFor(int);
+    method public void setMeasurer(androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+    method public void setOptimizationLevel(int);
+    method public void setPadding(int, int, int, int);
+    method public void setPass(int);
+    method public void setRtl(boolean);
+    method public boolean updateChildrenFromSolver(androidx.constraintlayout.core.LinearSystem!, boolean[]!);
+    method public void updateHierarchy();
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyGraph! mDependencyGraph;
+    field public boolean mGroupsWrapOptimized;
+    field public int mHorizontalChainsSize;
+    field public boolean mHorizontalWrapOptimized;
+    field public androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure! mMeasure;
+    field protected androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer! mMeasurer;
+    field public androidx.constraintlayout.core.Metrics! mMetrics;
+    field public boolean mSkipSolver;
+    field protected androidx.constraintlayout.core.LinearSystem! mSystem;
+    field public int mVerticalChainsSize;
+    field public boolean mVerticalWrapOptimized;
+    field public int mWrapFixedHeight;
+    field public int mWrapFixedWidth;
+  }
+
+  public class Flow extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public Flow();
+    method public float getMaxElementsWrap();
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalBias(float);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int HORIZONTAL_ALIGN_END = 1; // 0x1
+    field public static final int HORIZONTAL_ALIGN_START = 0; // 0x0
+    field public static final int VERTICAL_ALIGN_BASELINE = 3; // 0x3
+    field public static final int VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int VERTICAL_ALIGN_TOP = 0; // 0x0
+    field public static final int WRAP_ALIGNED = 2; // 0x2
+    field public static final int WRAP_CHAIN = 1; // 0x1
+    field public static final int WRAP_CHAIN_NEW = 3; // 0x3
+    field public static final int WRAP_NONE = 0; // 0x0
+  }
+
+  public class Guideline extends androidx.constraintlayout.core.widgets.ConstraintWidget {
+    ctor public Guideline();
+    method public void cyclePosition();
+    method public androidx.constraintlayout.core.widgets.ConstraintAnchor! getAnchor();
+    method public int getMinimumPosition();
+    method public int getOrientation();
+    method public int getRelativeBegin();
+    method public int getRelativeBehaviour();
+    method public int getRelativeEnd();
+    method public float getRelativePercent();
+    method public boolean isPercent();
+    method public void setFinalValue(int);
+    method public void setGuideBegin(int);
+    method public void setGuideEnd(int);
+    method public void setGuidePercent(float);
+    method public void setGuidePercent(int);
+    method public void setMinimumPosition(int);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int RELATIVE_BEGIN = 1; // 0x1
+    field public static final int RELATIVE_END = 2; // 0x2
+    field public static final int RELATIVE_PERCENT = 0; // 0x0
+    field public static final int RELATIVE_UNKNOWN = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field protected boolean mGuidelineUseRtl;
+    field protected int mRelativeBegin;
+    field protected int mRelativeEnd;
+    field protected float mRelativePercent;
+  }
+
+  public interface Helper {
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void removeAllIds();
+    method public void updateConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+  }
+
+  public class HelperWidget extends androidx.constraintlayout.core.widgets.ConstraintWidget implements androidx.constraintlayout.core.widgets.Helper {
+    ctor public HelperWidget();
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void addDependents(java.util.ArrayList!, int, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public int findGroupInDependents(int);
+    method public void removeAllIds();
+    method public void updateConstraints(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget![]! mWidgets;
+    field public int mWidgetsCount;
+  }
+
+  public class Optimizer {
+    ctor public Optimizer();
+    method public static final boolean enabled(int, int);
+    field public static final int OPTIMIZATION_BARRIER = 2; // 0x2
+    field public static final int OPTIMIZATION_CACHE_MEASURES = 256; // 0x100
+    field public static final int OPTIMIZATION_CHAIN = 4; // 0x4
+    field public static final int OPTIMIZATION_DEPENDENCY_ORDERING = 512; // 0x200
+    field public static final int OPTIMIZATION_DIMENSIONS = 8; // 0x8
+    field public static final int OPTIMIZATION_DIRECT = 1; // 0x1
+    field public static final int OPTIMIZATION_GRAPH = 64; // 0x40
+    field public static final int OPTIMIZATION_GRAPH_WRAP = 128; // 0x80
+    field public static final int OPTIMIZATION_GROUPING = 1024; // 0x400
+    field public static final int OPTIMIZATION_GROUPS = 32; // 0x20
+    field public static final int OPTIMIZATION_NONE = 0; // 0x0
+    field public static final int OPTIMIZATION_RATIO = 16; // 0x10
+    field public static final int OPTIMIZATION_STANDARD = 257; // 0x101
+  }
+
+  public class Placeholder extends androidx.constraintlayout.core.widgets.VirtualLayout {
+    ctor public Placeholder();
+  }
+
+  public class Rectangle {
+    ctor public Rectangle();
+    method public boolean contains(int, int);
+    method public int getCenterX();
+    method public int getCenterY();
+    method public void setBounds(int, int, int, int);
+    field public int height;
+    field public int width;
+    field public int x;
+    field public int y;
+  }
+
+  public class VirtualLayout extends androidx.constraintlayout.core.widgets.HelperWidget {
+    ctor public VirtualLayout();
+    method public void applyRtl(boolean);
+    method public void captureWidgets();
+    method public boolean contains(java.util.HashSet!);
+    method public int getMeasuredHeight();
+    method public int getMeasuredWidth();
+    method public int getPaddingBottom();
+    method public int getPaddingLeft();
+    method public int getPaddingRight();
+    method public int getPaddingTop();
+    method protected void measure(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, int, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, int);
+    method public void measure(int, int, int, int);
+    method protected boolean measureChildren();
+    method public boolean needSolverPass();
+    method protected void needsCallbackFromSolver(boolean);
+    method public void setMeasure(int, int);
+    method public void setPadding(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingEnd(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingStart(int);
+    method public void setPaddingTop(int);
+    field protected androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure! mMeasure;
+  }
+
+  public class WidgetContainer extends androidx.constraintlayout.core.widgets.ConstraintWidget {
+    ctor public WidgetContainer();
+    ctor public WidgetContainer(int, int);
+    ctor public WidgetContainer(int, int, int, int);
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void add(androidx.constraintlayout.core.widgets.ConstraintWidget!...!);
+    method public java.util.ArrayList! getChildren();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidgetContainer! getRootConstraintContainer();
+    method public void layout();
+    method public void remove(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void removeAllChildren();
+    field public java.util.ArrayList! mChildren;
+  }
+
+}
+
+package androidx.constraintlayout.core.widgets.analyzer {
+
+  public class BasicMeasure {
+    ctor public BasicMeasure(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public long solverMeasure(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int, int, int, int, int, int, int);
+    method public void updateHierarchy(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    field public static final int AT_MOST = -2147483648; // 0x80000000
+    field public static final int EXACTLY = 1073741824; // 0x40000000
+    field public static final int FIXED = -3; // 0xfffffffd
+    field public static final int MATCH_PARENT = -1; // 0xffffffff
+    field public static final int UNSPECIFIED = 0; // 0x0
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public static class BasicMeasure.Measure {
+    ctor public BasicMeasure.Measure();
+    field public static int SELF_DIMENSIONS;
+    field public static int TRY_GIVEN_DIMENSIONS;
+    field public static int USE_GIVEN_DIMENSIONS;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! horizontalBehavior;
+    field public int horizontalDimension;
+    field public int measureStrategy;
+    field public int measuredBaseline;
+    field public boolean measuredHasBaseline;
+    field public int measuredHeight;
+    field public boolean measuredNeedsSolverPass;
+    field public int measuredWidth;
+    field public androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! verticalBehavior;
+    field public int verticalDimension;
+  }
+
+  public static interface BasicMeasure.Measurer {
+    method public void didMeasures();
+    method public void measure(androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measure!);
+  }
+
+  public class ChainRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public ChainRun(androidx.constraintlayout.core.widgets.ConstraintWidget!, int);
+    method public void applyToWidget();
+  }
+
+  public interface Dependency {
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+  }
+
+  public class DependencyGraph {
+    ctor public DependencyGraph(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!);
+    method public void buildGraph();
+    method public void buildGraph(java.util.ArrayList!);
+    method public void defineTerminalWidgets(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+    method public boolean directMeasure(boolean);
+    method public boolean directMeasureSetup(boolean);
+    method public boolean directMeasureWithOrientation(boolean, int);
+    method public void invalidateGraph();
+    method public void invalidateMeasures();
+    method public void measureWidgets();
+    method public void setMeasurer(androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+  }
+
+  public class DependencyNode implements androidx.constraintlayout.core.widgets.analyzer.Dependency {
+    ctor public DependencyNode(androidx.constraintlayout.core.widgets.analyzer.WidgetRun!);
+    method public void addDependency(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method public void clear();
+    method public String! name();
+    method public void resolve(int);
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    field public boolean delegateToWidgetRun;
+    field public boolean readyToSolve;
+    field public boolean resolved;
+    field public androidx.constraintlayout.core.widgets.analyzer.Dependency! updateDelegate;
+    field public int value;
+  }
+
+  public class Direct {
+    ctor public Direct();
+    method public static String! ls(int);
+    method public static boolean solveChain(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.LinearSystem!, int, int, androidx.constraintlayout.core.widgets.ChainHead!, boolean, boolean, boolean);
+    method public static void solvingPass(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+  }
+
+  public class Grouping {
+    ctor public Grouping();
+    method public static androidx.constraintlayout.core.widgets.analyzer.WidgetGroup! findDependents(androidx.constraintlayout.core.widgets.ConstraintWidget!, int, java.util.ArrayList!, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public static boolean simpleSolvingPass(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.Measurer!);
+    method public static boolean validInGroup(androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!, androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour!);
+  }
+
+  public class HorizontalWidgetRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public HorizontalWidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void applyToWidget();
+  }
+
+  public class VerticalWidgetRun extends androidx.constraintlayout.core.widgets.analyzer.WidgetRun {
+    ctor public VerticalWidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void applyToWidget();
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! baseline;
+  }
+
+  public class WidgetGroup {
+    ctor public WidgetGroup(int);
+    method public boolean add(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method public void apply();
+    method public void cleanup(java.util.ArrayList!);
+    method public void clear();
+    method public int getId();
+    method public int getOrientation();
+    method public boolean intersectWith(androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public boolean isAuthoritative();
+    method public int measureWrap(androidx.constraintlayout.core.LinearSystem!, int);
+    method public void moveTo(int, androidx.constraintlayout.core.widgets.analyzer.WidgetGroup!);
+    method public void setAuthoritative(boolean);
+    method public void setOrientation(int);
+    method public int size();
+  }
+
+  public abstract class WidgetRun implements androidx.constraintlayout.core.widgets.analyzer.Dependency {
+    ctor public WidgetRun(androidx.constraintlayout.core.widgets.ConstraintWidget!);
+    method protected final void addTarget(androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, int);
+    method protected final void addTarget(androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, androidx.constraintlayout.core.widgets.analyzer.DependencyNode!, int, androidx.constraintlayout.core.widgets.analyzer.DimensionDependency!);
+    method protected final int getLimitedDimension(int, int);
+    method protected final androidx.constraintlayout.core.widgets.analyzer.DependencyNode! getTarget(androidx.constraintlayout.core.widgets.ConstraintAnchor!);
+    method protected final androidx.constraintlayout.core.widgets.analyzer.DependencyNode! getTarget(androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method public long getWrapDimension();
+    method public boolean isCenterConnection();
+    method public boolean isDimensionResolved();
+    method public boolean isResolved();
+    method public void update(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method protected void updateRunCenter(androidx.constraintlayout.core.widgets.analyzer.Dependency!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, androidx.constraintlayout.core.widgets.ConstraintAnchor!, int);
+    method protected void updateRunEnd(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method protected void updateRunStart(androidx.constraintlayout.core.widgets.analyzer.Dependency!);
+    method public long wrapSize(int);
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! end;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidget.DimensionBehaviour! mDimensionBehavior;
+    field protected androidx.constraintlayout.core.widgets.analyzer.WidgetRun.RunType! mRunType;
+    field public int matchConstraintsType;
+    field public int orientation;
+    field public androidx.constraintlayout.core.widgets.analyzer.DependencyNode! start;
+  }
+
+}
+
diff --git a/constraintlayout/constraintlayout/api/2.2.0-beta01.txt b/constraintlayout/constraintlayout/api/2.2.0-beta01.txt
new file mode 100644
index 0000000..2d187a8
--- /dev/null
+++ b/constraintlayout/constraintlayout/api/2.2.0-beta01.txt
@@ -0,0 +1,1714 @@
+// Signature format: 4.0
+package androidx.constraintlayout.helper.widget {
+
+  public class Carousel extends androidx.constraintlayout.motion.widget.MotionHelper {
+    ctor public Carousel(android.content.Context!);
+    ctor public Carousel(android.content.Context!, android.util.AttributeSet!);
+    ctor public Carousel(android.content.Context!, android.util.AttributeSet!, int);
+    method public int getCount();
+    method public int getCurrentIndex();
+    method public boolean isInfinite();
+    method public void jumpToIndex(int);
+    method public void refresh();
+    method public void setAdapter(androidx.constraintlayout.helper.widget.Carousel.Adapter!);
+    method public void setInfinite(boolean);
+    method public void transitionToIndex(int, int);
+    field public static final int TOUCH_UP_CARRY_ON = 2; // 0x2
+    field public static final int TOUCH_UP_IMMEDIATE_STOP = 1; // 0x1
+  }
+
+  public static interface Carousel.Adapter {
+    method public int count();
+    method public void onNewItem(int);
+    method public void populate(android.view.View!, int);
+  }
+
+  public class CircularFlow extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public CircularFlow(android.content.Context!);
+    ctor public CircularFlow(android.content.Context!, android.util.AttributeSet!);
+    ctor public CircularFlow(android.content.Context!, android.util.AttributeSet!, int);
+    method public void addViewToCircularFlow(android.view.View!, int, float);
+    method public float[]! getAngles();
+    method public int[]! getRadius();
+    method public boolean isUpdatable(android.view.View!);
+    method public void setDefaultAngle(float);
+    method public void setDefaultRadius(int);
+    method public void updateAngle(android.view.View!, float);
+    method public void updateRadius(android.view.View!, int);
+    method public void updateReference(android.view.View!, int, float);
+  }
+
+  public class Flow extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public Flow(android.content.Context!);
+    ctor public Flow(android.content.Context!, android.util.AttributeSet!);
+    ctor public Flow(android.content.Context!, android.util.AttributeSet!, int);
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setPadding(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingTop(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalBias(float);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int HORIZONTAL_ALIGN_END = 1; // 0x1
+    field public static final int HORIZONTAL_ALIGN_START = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_BASELINE = 3; // 0x3
+    field public static final int VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int VERTICAL_ALIGN_TOP = 0; // 0x0
+    field public static final int WRAP_ALIGNED = 2; // 0x2
+    field public static final int WRAP_CHAIN = 1; // 0x1
+    field public static final int WRAP_NONE = 0; // 0x0
+  }
+
+  public class Grid extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public Grid(android.content.Context!);
+    ctor public Grid(android.content.Context!, android.util.AttributeSet!);
+    ctor public Grid(android.content.Context!, android.util.AttributeSet!, int);
+    method public String! getColumnWeights();
+    method public int getColumns();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public String! getRowWeights();
+    method public int getRows();
+    method public String! getSkips();
+    method public String! getSpans();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String!);
+    method public void setColumns(int);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setRowWeights(String!);
+    method public void setRows(int);
+    method public void setSkips(String!);
+    method public void setSpans(CharSequence!);
+    method public void setVerticalGaps(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class Layer extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Layer(android.content.Context!);
+    ctor public Layer(android.content.Context!, android.util.AttributeSet!);
+    ctor public Layer(android.content.Context!, android.util.AttributeSet!, int);
+    method protected void calcCenters();
+    field protected float mComputedCenterX;
+    field protected float mComputedCenterY;
+    field protected float mComputedMaxX;
+    field protected float mComputedMaxY;
+    field protected float mComputedMinX;
+    field protected float mComputedMinY;
+  }
+
+  public class MotionEffect extends androidx.constraintlayout.motion.widget.MotionHelper {
+    ctor public MotionEffect(android.content.Context!);
+    ctor public MotionEffect(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionEffect(android.content.Context!, android.util.AttributeSet!, int);
+    field public static final int AUTO = -1; // 0xffffffff
+    field public static final int EAST = 2; // 0x2
+    field public static final int NORTH = 0; // 0x0
+    field public static final int SOUTH = 1; // 0x1
+    field public static final String TAG = "FadeMove";
+    field public static final int WEST = 3; // 0x3
+  }
+
+  public class MotionPlaceholder extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public MotionPlaceholder(android.content.Context!);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!, int, int);
+  }
+
+}
+
+package androidx.constraintlayout.motion.utils {
+
+  public class CustomSupport {
+    ctor public CustomSupport();
+    method public static void setInterpolatedValue(androidx.constraintlayout.widget.ConstraintAttribute!, android.view.View!, float[]!);
+  }
+
+  public class StopLogic extends androidx.constraintlayout.motion.widget.MotionInterpolator {
+    ctor public StopLogic();
+    method public void config(float, float, float, float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+    method public void springConfig(float, float, float, float, float, float, float, int);
+  }
+
+  public abstract class ViewOscillator extends androidx.constraintlayout.core.motion.utils.KeyCycleOscillator {
+    ctor public ViewOscillator();
+    method public static androidx.constraintlayout.motion.utils.ViewOscillator! makeSpline(String!);
+    method public abstract void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewOscillator.PathRotateSet extends androidx.constraintlayout.motion.utils.ViewOscillator {
+    ctor public ViewOscillator.PathRotateSet();
+    method public void setPathRotate(android.view.View!, float, double, double);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public abstract class ViewSpline extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public ViewSpline();
+    method public static androidx.constraintlayout.motion.utils.ViewSpline! makeCustomSpline(String!, android.util.SparseArray!);
+    method public static androidx.constraintlayout.motion.utils.ViewSpline! makeSpline(String!);
+    method public abstract void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewSpline.CustomSet extends androidx.constraintlayout.motion.utils.ViewSpline {
+    ctor public ViewSpline.CustomSet(String!, android.util.SparseArray!);
+    method public void setPoint(int, androidx.constraintlayout.widget.ConstraintAttribute!);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewSpline.PathRotate extends androidx.constraintlayout.motion.utils.ViewSpline {
+    ctor public ViewSpline.PathRotate();
+    method public void setPathRotate(android.view.View!, float, double, double);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public class ViewState {
+    ctor public ViewState();
+    method public void getState(android.view.View!);
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public float rotation;
+    field public int top;
+  }
+
+  public abstract class ViewTimeCycle extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public ViewTimeCycle();
+    method public float get(float, long, android.view.View!, androidx.constraintlayout.core.motion.utils.KeyCache!);
+    method public static androidx.constraintlayout.motion.utils.ViewTimeCycle! makeCustomSpline(String!, android.util.SparseArray!);
+    method public static androidx.constraintlayout.motion.utils.ViewTimeCycle! makeSpline(String!, long);
+    method public abstract boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class ViewTimeCycle.CustomSet extends androidx.constraintlayout.motion.utils.ViewTimeCycle {
+    ctor public ViewTimeCycle.CustomSet(String!, android.util.SparseArray!);
+    method public void setPoint(int, androidx.constraintlayout.widget.ConstraintAttribute!, float, int, float);
+    method public boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class ViewTimeCycle.PathRotate extends androidx.constraintlayout.motion.utils.ViewTimeCycle {
+    ctor public ViewTimeCycle.PathRotate();
+    method public boolean setPathRotate(android.view.View!, androidx.constraintlayout.core.motion.utils.KeyCache!, float, long, double, double);
+    method public boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+}
+
+package androidx.constraintlayout.motion.widget {
+
+  public interface Animatable {
+    method public float getProgress();
+    method public void setProgress(float);
+  }
+
+  public interface CustomFloatAttributes {
+    method public float get(String!);
+    method public String![]! getListOfAttributes();
+    method public void set(String!, float);
+  }
+
+  public class Debug {
+    ctor public Debug();
+    method public static void dumpLayoutParams(android.view.ViewGroup!, String!);
+    method public static void dumpLayoutParams(android.view.ViewGroup.LayoutParams!, String!);
+    method public static void dumpPoc(Object!);
+    method public static String! getActionType(android.view.MotionEvent!);
+    method public static String! getCallFrom(int);
+    method public static String! getLoc();
+    method public static String! getLocation();
+    method public static String! getLocation2();
+    method public static String! getName(android.content.Context!, int);
+    method public static String! getName(android.content.Context!, int[]!);
+    method public static String! getName(android.view.View!);
+    method public static String! getState(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public static String! getState(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public static void logStack(String!, String!, int);
+    method public static void printStack(String!, int);
+  }
+
+  public class DesignTool {
+    ctor public DesignTool(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public int designAccess(int, String!, Object!, float[]!, int, float[]!, int);
+    method public void disableAutoTransition(boolean);
+    method public void dumpConstraintSet(String!);
+    method public int getAnimationKeyFrames(Object!, float[]!);
+    method public int getAnimationPath(Object!, float[]!, int);
+    method public void getAnimationRectangles(Object!, float[]!);
+    method public String! getEndState();
+    method public int getKeyFrameInfo(Object!, int, int[]!);
+    method public float getKeyFramePosition(Object!, int, float, float);
+    method public int getKeyFramePositions(Object!, int[]!, float[]!);
+    method public Object! getKeyframe(int, int, int);
+    method public Object! getKeyframe(Object!, int, int);
+    method public Object! getKeyframeAtLocation(Object!, float, float);
+    method public Boolean! getPositionKeyframe(Object!, Object!, float, float, String![]!, float[]!);
+    method public float getProgress();
+    method public String! getStartState();
+    method public String! getState();
+    method public long getTransitionTimeMs();
+    method public boolean isInTransition();
+    method public void setAttributes(int, String!, Object!, Object!);
+    method public void setKeyFrame(Object!, int, String!, Object!);
+    method public boolean setKeyFramePosition(Object!, int, int, float, float);
+    method public void setKeyframe(Object!, String!, Object!);
+    method public void setState(String!);
+    method public void setToolPosition(float);
+    method public void setTransition(String!, String!);
+    method public void setViewDebug(Object!, int);
+  }
+
+  public interface FloatLayout {
+    method public void layout(float, float, float, float);
+  }
+
+  public abstract class Key {
+    ctor public Key();
+    method public abstract void addValues(java.util.HashMap!);
+    method public abstract androidx.constraintlayout.motion.widget.Key! clone();
+    method public androidx.constraintlayout.motion.widget.Key! copy(androidx.constraintlayout.motion.widget.Key!);
+    method public int getFramePosition();
+    method public void setFramePosition(int);
+    method public void setInterpolation(java.util.HashMap!);
+    method public abstract void setValue(String!, Object!);
+    method public androidx.constraintlayout.motion.widget.Key! setViewId(int);
+    field public static final String ALPHA = "alpha";
+    field public static final String CURVEFIT = "curveFit";
+    field public static final String CUSTOM = "CUSTOM";
+    field public static final String ELEVATION = "elevation";
+    field public static final String MOTIONPROGRESS = "motionProgress";
+    field public static final String PIVOT_X = "transformPivotX";
+    field public static final String PIVOT_Y = "transformPivotY";
+    field public static final String PROGRESS = "progress";
+    field public static final String ROTATION = "rotation";
+    field public static final String ROTATION_X = "rotationX";
+    field public static final String ROTATION_Y = "rotationY";
+    field public static final String SCALE_X = "scaleX";
+    field public static final String SCALE_Y = "scaleY";
+    field public static final String TRANSITIONEASING = "transitionEasing";
+    field public static final String TRANSITION_PATH_ROTATE = "transitionPathRotate";
+    field public static final String TRANSLATION_X = "translationX";
+    field public static final String TRANSLATION_Y = "translationY";
+    field public static final String TRANSLATION_Z = "translationZ";
+    field public static int UNSET;
+    field public static final String VISIBILITY = "visibility";
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_VARIES_BY = "waveVariesBy";
+    field protected int mType;
+  }
+
+  public class KeyAttributes extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyAttributes();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 1; // 0x1
+  }
+
+  public class KeyCycle extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyCycle();
+    method public void addCycleValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public float getValue(String!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 4; // 0x4
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class KeyFrames {
+    ctor public KeyFrames();
+    ctor public KeyFrames(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void addAllFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public void addFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public void addKey(androidx.constraintlayout.motion.widget.Key!);
+    method public java.util.ArrayList! getKeyFramesForView(int);
+    method public java.util.Set! getKeys();
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public class KeyPosition extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyPosition();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public boolean intersects(int, int, android.graphics.RectF!, android.graphics.RectF!, float, float);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void positionAttributes(android.view.View!, android.graphics.RectF!, android.graphics.RectF!, float, float, String![]!, float[]!);
+    method public void setType(int);
+    method public void setValue(String!, Object!);
+    field public static final String DRAWPATH = "drawPath";
+    field public static final String PERCENT_HEIGHT = "percentHeight";
+    field public static final String PERCENT_WIDTH = "percentWidth";
+    field public static final String PERCENT_X = "percentX";
+    field public static final String PERCENT_Y = "percentY";
+    field public static final String SIZE_PERCENT = "sizePercent";
+    field public static final String TRANSITION_EASING = "transitionEasing";
+    field public static final int TYPE_AXIS = 3; // 0x3
+    field public static final int TYPE_CARTESIAN = 0; // 0x0
+    field public static final int TYPE_PATH = 1; // 0x1
+    field public static final int TYPE_SCREEN = 2; // 0x2
+  }
+
+  public class KeyTimeCycle extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyTimeCycle();
+    method public void addTimeValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 3; // 0x3
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class KeyTrigger extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyTrigger();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void conditionallyFire(float, android.view.View!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final String CROSS = "CROSS";
+    field public static final int KEY_TYPE = 5; // 0x5
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+  public class MotionController {
+    method public void addKey(androidx.constraintlayout.motion.widget.Key!);
+    method public int getAnimateRelativeTo();
+    method public void getCenter(double, float[]!, float[]!);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public int getDrawPath();
+    method public float getFinalHeight();
+    method public float getFinalWidth();
+    method public float getFinalX();
+    method public float getFinalY();
+    method public int getKeyFrameInfo(int, int[]!);
+    method public int getKeyFramePositions(int[]!, float[]!);
+    method public float getStartHeight();
+    method public float getStartWidth();
+    method public float getStartX();
+    method public float getStartY();
+    method public int getTransformPivotTarget();
+    method public android.view.View! getView();
+    method public void remeasure();
+    method public void setDrawPath(int);
+    method public void setPathMotionArc(int);
+    method public void setStartState(androidx.constraintlayout.motion.utils.ViewState!, android.view.View!, int, int, int);
+    method public void setTransformPivotTarget(int);
+    method public void setView(android.view.View!);
+    method public void setup(int, int, float, long);
+    method public void setupRelative(androidx.constraintlayout.motion.widget.MotionController!);
+    field public static final int DRAW_PATH_AS_CONFIGURED = 4; // 0x4
+    field public static final int DRAW_PATH_BASIC = 1; // 0x1
+    field public static final int DRAW_PATH_CARTESIAN = 3; // 0x3
+    field public static final int DRAW_PATH_NONE = 0; // 0x0
+    field public static final int DRAW_PATH_RECTANGLE = 5; // 0x5
+    field public static final int DRAW_PATH_RELATIVE = 2; // 0x2
+    field public static final int DRAW_PATH_SCREEN = 6; // 0x6
+    field public static final int HORIZONTAL_PATH_X = 2; // 0x2
+    field public static final int HORIZONTAL_PATH_Y = 3; // 0x3
+    field public static final int PATH_PERCENT = 0; // 0x0
+    field public static final int PATH_PERPENDICULAR = 1; // 0x1
+    field public static final int ROTATION_LEFT = 2; // 0x2
+    field public static final int ROTATION_RIGHT = 1; // 0x1
+    field public static final int VERTICAL_PATH_X = 4; // 0x4
+    field public static final int VERTICAL_PATH_Y = 5; // 0x5
+  }
+
+  public class MotionHelper extends androidx.constraintlayout.widget.ConstraintHelper implements androidx.constraintlayout.motion.widget.MotionHelperInterface {
+    ctor public MotionHelper(android.content.Context!);
+    ctor public MotionHelper(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionHelper(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getProgress();
+    method public boolean isDecorator();
+    method public boolean isUseOnHide();
+    method public boolean isUsedOnShow();
+    method public void onFinishedMotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void onPostDraw(android.graphics.Canvas!);
+    method public void onPreDraw(android.graphics.Canvas!);
+    method public void onPreSetup(androidx.constraintlayout.motion.widget.MotionLayout!, java.util.HashMap!);
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+    method public void setProgress(android.view.View!, float);
+    method public void setProgress(float);
+    field protected android.view.View![]! views;
+  }
+
+  public interface MotionHelperInterface extends androidx.constraintlayout.motion.widget.Animatable androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener {
+    method public boolean isDecorator();
+    method public boolean isUseOnHide();
+    method public boolean isUsedOnShow();
+    method public void onFinishedMotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void onPostDraw(android.graphics.Canvas!);
+    method public void onPreDraw(android.graphics.Canvas!);
+    method public void onPreSetup(androidx.constraintlayout.motion.widget.MotionLayout!, java.util.HashMap!);
+  }
+
+  public abstract class MotionInterpolator implements android.view.animation.Interpolator {
+    ctor public MotionInterpolator();
+    method public abstract float getVelocity();
+  }
+
+  public class MotionLayout extends androidx.constraintlayout.widget.ConstraintLayout implements androidx.core.view.NestedScrollingParent3 {
+    ctor public MotionLayout(android.content.Context);
+    ctor public MotionLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public MotionLayout(android.content.Context, android.util.AttributeSet?, int);
+    method public void addTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public boolean applyViewTransition(int, androidx.constraintlayout.motion.widget.MotionController!);
+    method public androidx.constraintlayout.widget.ConstraintSet! cloneConstraintSet(int);
+    method public void enableTransition(int, boolean);
+    method public void enableViewTransition(int, boolean);
+    method protected void fireTransitionCompleted();
+    method public void fireTrigger(int, boolean, float);
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet(int);
+    method @IdRes public int[]! getConstraintSetIds();
+    method public int getCurrentState();
+    method public java.util.ArrayList! getDefinedTransitions();
+    method public androidx.constraintlayout.motion.widget.DesignTool! getDesignTool();
+    method public int getEndState();
+    method public int[]! getMatchingConstraintSetIds(java.lang.String!...!);
+    method protected long getNanoTime();
+    method public float getProgress();
+    method public androidx.constraintlayout.motion.widget.MotionScene! getScene();
+    method public int getStartState();
+    method public float getTargetPosition();
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! getTransition(int);
+    method public android.os.Bundle! getTransitionState();
+    method public long getTransitionTimeMs();
+    method public float getVelocity();
+    method public void getViewVelocity(android.view.View!, float, float, float[]!, int);
+    method public boolean isDelayedApplicationOfInitialState();
+    method public boolean isInRotation();
+    method public boolean isInteractionEnabled();
+    method public boolean isViewTransitionEnabled(int);
+    method public void jumpToState(int);
+    method protected androidx.constraintlayout.motion.widget.MotionLayout.MotionTracker! obtainVelocityTracker();
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]!);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method @Deprecated public void rebuildMotion();
+    method public void rebuildScene();
+    method public boolean removeTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public void rotateTo(int, int);
+    method public void scheduleTransitionTo(int);
+    method public void setDebugMode(int);
+    method public void setDelayedApplicationOfInitialState(boolean);
+    method public void setInteractionEnabled(boolean);
+    method public void setInterpolatedProgress(float);
+    method public void setOnHide(float);
+    method public void setOnShow(float);
+    method public void setProgress(float);
+    method public void setProgress(float, float);
+    method public void setScene(androidx.constraintlayout.motion.widget.MotionScene!);
+    method protected void setTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void setTransition(int);
+    method public void setTransition(int, int);
+    method public void setTransitionDuration(int);
+    method public void setTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public void setTransitionState(android.os.Bundle!);
+    method public void touchAnimateTo(int, float, float);
+    method public void touchSpringTo(float, float);
+    method public void transitionToEnd();
+    method public void transitionToEnd(Runnable!);
+    method public void transitionToStart();
+    method public void transitionToStart(Runnable!);
+    method public void transitionToState(int);
+    method public void transitionToState(int, int);
+    method public void transitionToState(int, int, int);
+    method public void transitionToState(int, int, int, int);
+    method public void updateState();
+    method public void updateState(int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public void updateStateAnimate(int, androidx.constraintlayout.widget.ConstraintSet!, int);
+    method public void viewTransition(int, android.view.View!...!);
+    field public static final int DEBUG_SHOW_NONE = 0; // 0x0
+    field public static final int DEBUG_SHOW_PATH = 2; // 0x2
+    field public static final int DEBUG_SHOW_PROGRESS = 1; // 0x1
+    field public static boolean IS_IN_EDIT_MODE;
+    field public static final int TOUCH_UP_COMPLETE = 0; // 0x0
+    field public static final int TOUCH_UP_COMPLETE_TO_END = 2; // 0x2
+    field public static final int TOUCH_UP_COMPLETE_TO_START = 1; // 0x1
+    field public static final int TOUCH_UP_DECELERATE = 4; // 0x4
+    field public static final int TOUCH_UP_DECELERATE_AND_COMPLETE = 5; // 0x5
+    field public static final int TOUCH_UP_NEVER_TO_END = 7; // 0x7
+    field public static final int TOUCH_UP_NEVER_TO_START = 6; // 0x6
+    field public static final int TOUCH_UP_STOP = 3; // 0x3
+    field public static final int VELOCITY_LAYOUT = 1; // 0x1
+    field public static final int VELOCITY_POST_LAYOUT = 0; // 0x0
+    field public static final int VELOCITY_STATIC_LAYOUT = 3; // 0x3
+    field public static final int VELOCITY_STATIC_POST_LAYOUT = 2; // 0x2
+    field protected boolean mMeasureDuringTransition;
+  }
+
+  protected static interface MotionLayout.MotionTracker {
+    method public void addMovement(android.view.MotionEvent!);
+    method public void clear();
+    method public void computeCurrentVelocity(int);
+    method public void computeCurrentVelocity(int, float);
+    method public float getXVelocity();
+    method public float getXVelocity(int);
+    method public float getYVelocity();
+    method public float getYVelocity(int);
+    method public void recycle();
+  }
+
+  public static interface MotionLayout.TransitionListener {
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+  }
+
+  public class MotionScene {
+    ctor public MotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void addOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void addTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public boolean applyViewTransition(int, androidx.constraintlayout.motion.widget.MotionController!);
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! bestTransitionFor(int, float, float, android.view.MotionEvent!);
+    method public void disableAutoTransition(boolean);
+    method public void enableViewTransition(int, boolean);
+    method public int gatPathMotionArc();
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet(android.content.Context!, String!);
+    method public int[]! getConstraintSetIds();
+    method public java.util.ArrayList! getDefinedTransitions();
+    method public int getDuration();
+    method public android.view.animation.Interpolator! getInterpolator();
+    method public void getKeyFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public int[]! getMatchingStateLabels(java.lang.String!...!);
+    method public float getPathPercent(android.view.View!, int);
+    method public float getStaggered();
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! getTransitionById(int);
+    method public java.util.List! getTransitionsWithState(int);
+    method public boolean isViewTransitionEnabled(int);
+    method public int lookUpConstraintId(String!);
+    method public String! lookUpConstraintName(int);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void removeTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void setConstraintSet(int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public void setDuration(int);
+    method public void setKeyframe(android.view.View!, int, String!, Object!);
+    method public void setRtl(boolean);
+    method public void setTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public static String! stripID(String!);
+    method public boolean validateLayout(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void viewTransition(int, android.view.View!...!);
+    field public static final int LAYOUT_CALL_MEASURE = 2; // 0x2
+    field public static final int LAYOUT_HONOR_REQUEST = 1; // 0x1
+    field public static final int LAYOUT_IGNORE_REQUEST = 0; // 0x0
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public static class MotionScene.Transition {
+    ctor public MotionScene.Transition(int, androidx.constraintlayout.motion.widget.MotionScene!, int, int);
+    method public void addKeyFrame(androidx.constraintlayout.motion.widget.KeyFrames!);
+    method public void addOnClick(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void addOnClick(int, int);
+    method public String! debugString(android.content.Context!);
+    method public int getAutoTransition();
+    method public int getDuration();
+    method public int getEndConstraintSetId();
+    method public int getId();
+    method public java.util.List! getKeyFrameList();
+    method public int getLayoutDuringTransition();
+    method public java.util.List! getOnClickList();
+    method public int getPathMotionArc();
+    method public float getStagger();
+    method public int getStartConstraintSetId();
+    method public androidx.constraintlayout.motion.widget.TouchResponse! getTouchResponse();
+    method public boolean isEnabled();
+    method public boolean isTransitionFlag(int);
+    method public void removeOnClick(int);
+    method public void setAutoTransition(int);
+    method public void setDuration(int);
+    method public void setEnabled(boolean);
+    method public void setInterpolatorInfo(int, String!, int);
+    method public void setLayoutDuringTransition(int);
+    method public void setOnSwipe(androidx.constraintlayout.motion.widget.OnSwipe!);
+    method public void setOnTouchUp(int);
+    method public void setPathMotionArc(int);
+    method public void setStagger(float);
+    method public void setTransitionFlag(int);
+    field public static final int AUTO_ANIMATE_TO_END = 4; // 0x4
+    field public static final int AUTO_ANIMATE_TO_START = 3; // 0x3
+    field public static final int AUTO_JUMP_TO_END = 2; // 0x2
+    field public static final int AUTO_JUMP_TO_START = 1; // 0x1
+    field public static final int AUTO_NONE = 0; // 0x0
+    field public static final int INTERPOLATE_ANTICIPATE = 6; // 0x6
+    field public static final int INTERPOLATE_BOUNCE = 4; // 0x4
+    field public static final int INTERPOLATE_EASE_IN = 1; // 0x1
+    field public static final int INTERPOLATE_EASE_IN_OUT = 0; // 0x0
+    field public static final int INTERPOLATE_EASE_OUT = 2; // 0x2
+    field public static final int INTERPOLATE_LINEAR = 3; // 0x3
+    field public static final int INTERPOLATE_OVERSHOOT = 5; // 0x5
+    field public static final int INTERPOLATE_REFERENCE_ID = -2; // 0xfffffffe
+    field public static final int INTERPOLATE_SPLINE_STRING = -1; // 0xffffffff
+  }
+
+  public static class MotionScene.Transition.TransitionOnClick implements android.view.View.OnClickListener {
+    ctor public MotionScene.Transition.TransitionOnClick(android.content.Context!, androidx.constraintlayout.motion.widget.MotionScene.Transition!, org.xmlpull.v1.XmlPullParser!);
+    ctor public MotionScene.Transition.TransitionOnClick(androidx.constraintlayout.motion.widget.MotionScene.Transition!, int, int);
+    method public void addOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!, int, androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void onClick(android.view.View!);
+    method public void removeOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!);
+    field public static final int ANIM_TOGGLE = 17; // 0x11
+    field public static final int ANIM_TO_END = 1; // 0x1
+    field public static final int ANIM_TO_START = 16; // 0x10
+    field public static final int JUMP_TO_END = 256; // 0x100
+    field public static final int JUMP_TO_START = 4096; // 0x1000
+  }
+
+  public class OnSwipe {
+    ctor public OnSwipe();
+    method public int getAutoCompleteMode();
+    method public int getDragDirection();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public int getLimitBoundsTo();
+    method public float getMaxAcceleration();
+    method public float getMaxVelocity();
+    method public boolean getMoveWhenScrollAtTop();
+    method public int getNestedScrollFlags();
+    method public int getOnTouchUp();
+    method public int getRotationCenterId();
+    method public int getSpringBoundary();
+    method public float getSpringDamping();
+    method public float getSpringMass();
+    method public float getSpringStiffness();
+    method public float getSpringStopThreshold();
+    method public int getTouchAnchorId();
+    method public int getTouchAnchorSide();
+    method public int getTouchRegionId();
+    method public void setAutoCompleteMode(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragDirection(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragScale(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragThreshold(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setLimitBoundsTo(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMaxAcceleration(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMaxVelocity(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMoveWhenScrollAtTop(boolean);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setNestedScrollFlags(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setOnTouchUp(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setRotateCenter(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringBoundary(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringDamping(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringMass(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringStiffness(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringStopThreshold(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchAnchorId(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchAnchorSide(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchRegionId(int);
+    field public static final int COMPLETE_MODE_CONTINUOUS_VELOCITY = 0; // 0x0
+    field public static final int COMPLETE_MODE_SPRING = 1; // 0x1
+    field public static final int DRAG_ANTICLOCKWISE = 7; // 0x7
+    field public static final int DRAG_CLOCKWISE = 6; // 0x6
+    field public static final int DRAG_DOWN = 1; // 0x1
+    field public static final int DRAG_END = 5; // 0x5
+    field public static final int DRAG_LEFT = 2; // 0x2
+    field public static final int DRAG_RIGHT = 3; // 0x3
+    field public static final int DRAG_START = 4; // 0x4
+    field public static final int DRAG_UP = 0; // 0x0
+    field public static final int FLAG_DISABLE_POST_SCROLL = 1; // 0x1
+    field public static final int FLAG_DISABLE_SCROLL = 2; // 0x2
+    field public static final int ON_UP_AUTOCOMPLETE = 0; // 0x0
+    field public static final int ON_UP_AUTOCOMPLETE_TO_END = 2; // 0x2
+    field public static final int ON_UP_AUTOCOMPLETE_TO_START = 1; // 0x1
+    field public static final int ON_UP_DECELERATE = 4; // 0x4
+    field public static final int ON_UP_DECELERATE_AND_COMPLETE = 5; // 0x5
+    field public static final int ON_UP_NEVER_TO_END = 7; // 0x7
+    field public static final int ON_UP_NEVER_TO_START = 6; // 0x6
+    field public static final int ON_UP_STOP = 3; // 0x3
+    field public static final int SIDE_BOTTOM = 3; // 0x3
+    field public static final int SIDE_END = 6; // 0x6
+    field public static final int SIDE_LEFT = 1; // 0x1
+    field public static final int SIDE_MIDDLE = 4; // 0x4
+    field public static final int SIDE_RIGHT = 2; // 0x2
+    field public static final int SIDE_START = 5; // 0x5
+    field public static final int SIDE_TOP = 0; // 0x0
+    field public static final int SPRING_BOUNDARY_BOUNCEBOTH = 3; // 0x3
+    field public static final int SPRING_BOUNDARY_BOUNCEEND = 2; // 0x2
+    field public static final int SPRING_BOUNDARY_BOUNCESTART = 1; // 0x1
+    field public static final int SPRING_BOUNDARY_OVERSHOOT = 0; // 0x0
+  }
+
+  public abstract class TransitionAdapter implements androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener {
+    ctor public TransitionAdapter();
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+  }
+
+  public class TransitionBuilder {
+    ctor public TransitionBuilder();
+    method public static androidx.constraintlayout.motion.widget.MotionScene.Transition! buildTransition(androidx.constraintlayout.motion.widget.MotionScene!, int, int, androidx.constraintlayout.widget.ConstraintSet!, int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public static void validate(androidx.constraintlayout.motion.widget.MotionLayout!);
+  }
+
+  public class ViewTransition {
+    method public int getSharedValue();
+    method public int getSharedValueCurrent();
+    method public int getSharedValueID();
+    method public int getStateTransition();
+    method public void setSharedValue(int);
+    method public void setSharedValueCurrent(int);
+    method public void setSharedValueID(int);
+    method public void setStateTransition(int);
+    field public static final String CONSTRAINT_OVERRIDE = "ConstraintOverride";
+    field public static final String CUSTOM_ATTRIBUTE = "CustomAttribute";
+    field public static final String CUSTOM_METHOD = "CustomMethod";
+    field public static final String KEY_FRAME_SET_TAG = "KeyFrameSet";
+    field public static final int ONSTATE_ACTION_DOWN = 1; // 0x1
+    field public static final int ONSTATE_ACTION_DOWN_UP = 3; // 0x3
+    field public static final int ONSTATE_ACTION_UP = 2; // 0x2
+    field public static final int ONSTATE_SHARED_VALUE_SET = 4; // 0x4
+    field public static final int ONSTATE_SHARED_VALUE_UNSET = 5; // 0x5
+    field public static final String VIEW_TRANSITION_TAG = "ViewTransition";
+  }
+
+  public class ViewTransitionController {
+    ctor public ViewTransitionController(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void add(androidx.constraintlayout.motion.widget.ViewTransition!);
+  }
+
+}
+
+package androidx.constraintlayout.utils.widget {
+
+  public class ImageFilterButton extends androidx.appcompat.widget.AppCompatImageButton {
+    ctor public ImageFilterButton(android.content.Context!);
+    ctor public ImageFilterButton(android.content.Context!, android.util.AttributeSet!);
+    ctor public ImageFilterButton(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getContrast();
+    method public float getCrossfade();
+    method public float getImagePanX();
+    method public float getImagePanY();
+    method public float getImageRotate();
+    method public float getImageZoom();
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getSaturation();
+    method public float getWarmth();
+    method public void setAltImageResource(int);
+    method public void setBrightness(float);
+    method public void setContrast(float);
+    method public void setCrossfade(float);
+    method public void setImagePanX(float);
+    method public void setImagePanY(float);
+    method public void setImageRotate(float);
+    method public void setImageZoom(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setSaturation(float);
+    method public void setWarmth(float);
+  }
+
+  public class ImageFilterView extends androidx.appcompat.widget.AppCompatImageView {
+    ctor public ImageFilterView(android.content.Context!);
+    ctor public ImageFilterView(android.content.Context!, android.util.AttributeSet!);
+    ctor public ImageFilterView(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getBrightness();
+    method public float getContrast();
+    method public float getCrossfade();
+    method public float getImagePanX();
+    method public float getImagePanY();
+    method public float getImageRotate();
+    method public float getImageZoom();
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getSaturation();
+    method public float getWarmth();
+    method public void setAltImageDrawable(android.graphics.drawable.Drawable!);
+    method public void setAltImageResource(int);
+    method public void setBrightness(float);
+    method public void setContrast(float);
+    method public void setCrossfade(float);
+    method public void setImagePanX(float);
+    method public void setImagePanY(float);
+    method public void setImageRotate(float);
+    method public void setImageZoom(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setSaturation(float);
+    method public void setWarmth(float);
+  }
+
+  public class MockView extends android.view.View {
+    ctor public MockView(android.content.Context!);
+    ctor public MockView(android.content.Context!, android.util.AttributeSet!);
+    ctor public MockView(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onDraw(android.graphics.Canvas);
+    field protected String! mText;
+  }
+
+  public class MotionButton extends androidx.appcompat.widget.AppCompatButton {
+    ctor public MotionButton(android.content.Context!);
+    ctor public MotionButton(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionButton(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getRound();
+    method public float getRoundPercent();
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+  }
+
+  public class MotionLabel extends android.view.View implements androidx.constraintlayout.motion.widget.FloatLayout {
+    ctor public MotionLabel(android.content.Context!);
+    ctor public MotionLabel(android.content.Context!, android.util.AttributeSet?);
+    ctor public MotionLabel(android.content.Context!, android.util.AttributeSet?, int);
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getScaleFromTextSize();
+    method public float getTextBackgroundPanX();
+    method public float getTextBackgroundPanY();
+    method public float getTextBackgroundRotate();
+    method public float getTextBackgroundZoom();
+    method public int getTextOutlineColor();
+    method public float getTextPanX();
+    method public float getTextPanY();
+    method public float getTextureHeight();
+    method public float getTextureWidth();
+    method public android.graphics.Typeface! getTypeface();
+    method public void layout(float, float, float, float);
+    method public void setGravity(int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setScaleFromTextSize(float);
+    method public void setText(CharSequence!);
+    method public void setTextBackgroundPanX(float);
+    method public void setTextBackgroundPanY(float);
+    method public void setTextBackgroundRotate(float);
+    method public void setTextBackgroundZoom(float);
+    method public void setTextFillColor(int);
+    method public void setTextOutlineColor(int);
+    method public void setTextOutlineThickness(float);
+    method public void setTextPanX(float);
+    method public void setTextPanY(float);
+    method public void setTextSize(float);
+    method public void setTextureHeight(float);
+    method public void setTextureWidth(float);
+    method public void setTypeface(android.graphics.Typeface!);
+  }
+
+  public class MotionTelltales extends androidx.constraintlayout.utils.widget.MockView {
+    ctor public MotionTelltales(android.content.Context!);
+    ctor public MotionTelltales(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionTelltales(android.content.Context!, android.util.AttributeSet!, int);
+    method public void setText(CharSequence!);
+  }
+
+}
+
+package androidx.constraintlayout.widget {
+
+  public class Barrier extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Barrier(android.content.Context!);
+    ctor public Barrier(android.content.Context!, android.util.AttributeSet!);
+    ctor public Barrier(android.content.Context!, android.util.AttributeSet!, int);
+    method @Deprecated public boolean allowsGoneWidget();
+    method public boolean getAllowsGoneWidget();
+    method public int getMargin();
+    method public int getType();
+    method public void setAllowsGoneWidget(boolean);
+    method public void setDpMargin(int);
+    method public void setMargin(int);
+    method public void setType(int);
+    field public static final int BOTTOM = 3; // 0x3
+    field public static final int END = 6; // 0x6
+    field public static final int LEFT = 0; // 0x0
+    field public static final int RIGHT = 1; // 0x1
+    field public static final int START = 5; // 0x5
+    field public static final int TOP = 2; // 0x2
+  }
+
+  public class ConstraintAttribute {
+    ctor public ConstraintAttribute(androidx.constraintlayout.widget.ConstraintAttribute!, Object!);
+    ctor public ConstraintAttribute(String!, androidx.constraintlayout.widget.ConstraintAttribute.AttributeType!);
+    ctor public ConstraintAttribute(String!, androidx.constraintlayout.widget.ConstraintAttribute.AttributeType!, Object!, boolean);
+    method public void applyCustom(android.view.View!);
+    method public boolean diff(androidx.constraintlayout.widget.ConstraintAttribute!);
+    method public static java.util.HashMap! extractAttributes(java.util.HashMap!, android.view.View!);
+    method public int getColorValue();
+    method public float getFloatValue();
+    method public int getIntegerValue();
+    method public String! getName();
+    method public String! getStringValue();
+    method public androidx.constraintlayout.widget.ConstraintAttribute.AttributeType! getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public boolean isBooleanValue();
+    method public boolean isContinuous();
+    method public boolean isMethod();
+    method public int numberOfInterpolatedValues();
+    method public static void parse(android.content.Context!, org.xmlpull.v1.XmlPullParser!, java.util.HashMap!);
+    method public static void setAttributes(android.view.View!, java.util.HashMap!);
+    method public void setColorValue(int);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public enum ConstraintAttribute.AttributeType {
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType BOOLEAN_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType COLOR_DRAWABLE_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType COLOR_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType DIMENSION_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType FLOAT_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType INT_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType REFERENCE_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType STRING_TYPE;
+  }
+
+  public abstract class ConstraintHelper extends android.view.View {
+    ctor public ConstraintHelper(android.content.Context!);
+    ctor public ConstraintHelper(android.content.Context!, android.util.AttributeSet!);
+    ctor public ConstraintHelper(android.content.Context!, android.util.AttributeSet!, int);
+    method public void addView(android.view.View!);
+    method public void applyHelperParams();
+    method protected void applyLayoutFeatures();
+    method protected void applyLayoutFeatures(androidx.constraintlayout.widget.ConstraintLayout!);
+    method protected void applyLayoutFeaturesInConstraintSet(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public boolean containsId(int);
+    method public int[]! getReferencedIds();
+    method protected android.view.View![]! getViews(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public int indexFromId(int);
+    method protected void init(android.util.AttributeSet!);
+    method public static boolean isChildOfHelper(android.view.View!);
+    method public void loadParameters(androidx.constraintlayout.widget.ConstraintSet.Constraint!, androidx.constraintlayout.core.widgets.HelperWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method public void onDraw(android.graphics.Canvas);
+    method public int removeView(android.view.View!);
+    method public void resolveRtl(androidx.constraintlayout.core.widgets.ConstraintWidget!, boolean);
+    method protected void setIds(String!);
+    method protected void setReferenceTags(String!);
+    method public void setReferencedIds(int[]!);
+    method public void updatePostConstraints(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePostLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreDraw(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreLayout(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.Helper!, android.util.SparseArray!);
+    method public void updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void validateParams();
+    field protected static final String CHILD_TAG = "CONSTRAINT_LAYOUT_HELPER_CHILD";
+    field protected int mCount;
+    field protected androidx.constraintlayout.core.widgets.Helper! mHelperWidget;
+    field protected int[]! mIds;
+    field protected java.util.HashMap! mMap;
+    field protected String! mReferenceIds;
+    field protected String! mReferenceTags;
+    field protected boolean mUseViewMeasure;
+    field protected android.content.Context! myContext;
+  }
+
+  public class ConstraintLayout extends android.view.ViewGroup {
+    ctor public ConstraintLayout(android.content.Context);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?, int);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?, int, int);
+    method public void addValueModifier(androidx.constraintlayout.widget.ConstraintLayout.ValueModifier!);
+    method protected void applyConstraintsFromLayoutParams(boolean, android.view.View!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method protected boolean dynamicUpdateConstraints(int, int);
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method protected androidx.constraintlayout.widget.ConstraintLayout.LayoutParams! generateDefaultLayoutParams();
+    method public androidx.constraintlayout.widget.ConstraintLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+    method public Object! getDesignInformation(int, Object!);
+    method public int getMaxHeight();
+    method public int getMaxWidth();
+    method public int getMinHeight();
+    method public int getMinWidth();
+    method public int getOptimizationLevel();
+    method public String! getSceneString();
+    method public static androidx.constraintlayout.widget.SharedValues! getSharedValues();
+    method public android.view.View! getViewById(int);
+    method public final androidx.constraintlayout.core.widgets.ConstraintWidget! getViewWidget(android.view.View!);
+    method protected boolean isRtl();
+    method public void loadLayoutDescription(int);
+    method protected void parseLayoutDescription(int);
+    method protected void resolveMeasuredDimension(int, int, int, int, boolean, boolean);
+    method protected void resolveSystem(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int);
+    method public void setConstraintSet(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void setDesignInformation(int, Object!, Object!);
+    method public void setMaxHeight(int);
+    method public void setMaxWidth(int);
+    method public void setMinHeight(int);
+    method public void setMinWidth(int);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public void setOptimizationLevel(int);
+    method protected void setSelfDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int, int);
+    method public void setState(int, int, int);
+    field public static final int DESIGN_INFO_ID = 0; // 0x0
+    field public static final String VERSION = "ConstraintLayout-2.2.0-alpha04";
+    field protected androidx.constraintlayout.widget.ConstraintLayoutStates! mConstraintLayoutSpec;
+    field protected boolean mDirtyHierarchy;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidgetContainer! mLayoutWidget;
+  }
+
+  public static class ConstraintLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ConstraintLayout.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public ConstraintLayout.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public ConstraintLayout.LayoutParams(int, int);
+    method public String! getConstraintTag();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public void reset();
+    method public void setWidgetDebugName(String!);
+    method public void validate();
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int CIRCLE = 8; // 0x8
+    field public static final int END = 7; // 0x7
+    field public static final int GONE_UNSET = -2147483648; // 0x80000000
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_HORIZONTAL_ONLY = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_INCLUDED = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_SKIPPED = 3; // 0x3
+    field public static final int WRAP_BEHAVIOR_VERTICAL_ONLY = 2; // 0x2
+    field public int baselineMargin;
+    field public int baselineToBaseline;
+    field public int baselineToBottom;
+    field public int baselineToTop;
+    field public int bottomToBottom;
+    field public int bottomToTop;
+    field public float circleAngle;
+    field public int circleConstraint;
+    field public int circleRadius;
+    field public boolean constrainedHeight;
+    field public boolean constrainedWidth;
+    field public String! constraintTag;
+    field public String! dimensionRatio;
+    field public int editorAbsoluteX;
+    field public int editorAbsoluteY;
+    field public int endToEnd;
+    field public int endToStart;
+    field public int goneBaselineMargin;
+    field public int goneBottomMargin;
+    field public int goneEndMargin;
+    field public int goneLeftMargin;
+    field public int goneRightMargin;
+    field public int goneStartMargin;
+    field public int goneTopMargin;
+    field public int guideBegin;
+    field public int guideEnd;
+    field public float guidePercent;
+    field public boolean guidelineUseRtl;
+    field public boolean helped;
+    field public float horizontalBias;
+    field public int horizontalChainStyle;
+    field public float horizontalWeight;
+    field public int leftToLeft;
+    field public int leftToRight;
+    field public int matchConstraintDefaultHeight;
+    field public int matchConstraintDefaultWidth;
+    field public int matchConstraintMaxHeight;
+    field public int matchConstraintMaxWidth;
+    field public int matchConstraintMinHeight;
+    field public int matchConstraintMinWidth;
+    field public float matchConstraintPercentHeight;
+    field public float matchConstraintPercentWidth;
+    field public int orientation;
+    field public int rightToLeft;
+    field public int rightToRight;
+    field public int startToEnd;
+    field public int startToStart;
+    field public int topToBottom;
+    field public int topToTop;
+    field public float verticalBias;
+    field public int verticalChainStyle;
+    field public float verticalWeight;
+    field public int wrapBehaviorInParent;
+  }
+
+  public static interface ConstraintLayout.ValueModifier {
+    method public boolean update(int, int, int, android.view.View!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+  }
+
+  public class ConstraintLayoutStates {
+    method public boolean needsToChange(int, float, float);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public void updateConstraints(int, float, float);
+    field public static final String TAG = "ConstraintLayoutStates";
+  }
+
+  public class ConstraintLayoutStatistics {
+    ctor public ConstraintLayoutStatistics(androidx.constraintlayout.widget.ConstraintLayout!);
+    ctor public ConstraintLayoutStatistics(androidx.constraintlayout.widget.ConstraintLayoutStatistics!);
+    method public void attach(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public androidx.constraintlayout.widget.ConstraintLayoutStatistics! clone();
+    method public void detach();
+    method public long getValue(int);
+    method public void logSummary(String!);
+    method public void logSummary(String!, androidx.constraintlayout.widget.ConstraintLayoutStatistics!);
+    method public void reset();
+    field public static final int DURATION_OF_CHILD_MEASURES = 5; // 0x5
+    field public static final int DURATION_OF_LAYOUT = 7; // 0x7
+    field public static final int DURATION_OF_MEASURES = 6; // 0x6
+    field public static final int NUMBER_OF_CHILD_MEASURES = 4; // 0x4
+    field public static final int NUMBER_OF_CHILD_VIEWS = 3; // 0x3
+    field public static final int NUMBER_OF_EQUATIONS = 9; // 0x9
+    field public static final int NUMBER_OF_LAYOUTS = 1; // 0x1
+    field public static final int NUMBER_OF_ON_MEASURES = 2; // 0x2
+    field public static final int NUMBER_OF_SIMPLE_EQUATIONS = 10; // 0xa
+    field public static final int NUMBER_OF_VARIABLES = 8; // 0x8
+  }
+
+  public class ConstraintProperties {
+    ctor public ConstraintProperties(android.view.View!);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToHorizontalChain(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToHorizontalChainRTL(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToVerticalChain(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! alpha(float);
+    method public void apply();
+    method public androidx.constraintlayout.widget.ConstraintProperties! center(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontally(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontally(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontallyRtl(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontallyRtl(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerVertically(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerVertically(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! connect(int, int, int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainDefaultHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainDefaultWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMaxHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMaxWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMinHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMinWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! dimensionRatio(String!);
+    method public androidx.constraintlayout.widget.ConstraintProperties! elevation(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! goneMargin(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalBias(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalChainStyle(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalWeight(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! margin(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeConstraints(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeFromHorizontalChain();
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeFromVerticalChain();
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotation(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotationX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotationY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! scaleX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! scaleY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivot(float, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivotX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivotY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translation(float, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationZ(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalBias(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalChainStyle(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalWeight(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! visibility(int);
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int END = 7; // 0x7
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public class ConstraintSet {
+    ctor public ConstraintSet();
+    method public void addColorAttributes(java.lang.String!...!);
+    method public void addFloatAttributes(java.lang.String!...!);
+    method public void addIntAttributes(java.lang.String!...!);
+    method public void addStringAttributes(java.lang.String!...!);
+    method public void addToHorizontalChain(int, int, int);
+    method public void addToHorizontalChainRTL(int, int, int);
+    method public void addToVerticalChain(int, int, int);
+    method public void applyCustomAttributes(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void applyDeltaFrom(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void applyTo(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void applyToHelper(androidx.constraintlayout.widget.ConstraintHelper!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method public void applyToLayoutParams(int, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+    method public void applyToWithoutCustom(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public static androidx.constraintlayout.widget.ConstraintSet.Constraint! buildDelta(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void center(int, int, int, int, int, int, int, float);
+    method public void centerHorizontally(int, int);
+    method public void centerHorizontally(int, int, int, int, int, int, int, float);
+    method public void centerHorizontallyRtl(int, int);
+    method public void centerHorizontallyRtl(int, int, int, int, int, int, int, float);
+    method public void centerVertically(int, int);
+    method public void centerVertically(int, int, int, int, int, int, int, float);
+    method public void clear(int);
+    method public void clear(int, int);
+    method public void clone(android.content.Context!, int);
+    method public void clone(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void clone(androidx.constraintlayout.widget.Constraints!);
+    method public void clone(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void connect(int, int, int, int);
+    method public void connect(int, int, int, int, int);
+    method public void constrainCircle(int, int, int, float);
+    method public void constrainDefaultHeight(int, int);
+    method public void constrainDefaultWidth(int, int);
+    method public void constrainHeight(int, int);
+    method public void constrainMaxHeight(int, int);
+    method public void constrainMaxWidth(int, int);
+    method public void constrainMinHeight(int, int);
+    method public void constrainMinWidth(int, int);
+    method public void constrainPercentHeight(int, float);
+    method public void constrainPercentWidth(int, float);
+    method public void constrainWidth(int, int);
+    method public void constrainedHeight(int, boolean);
+    method public void constrainedWidth(int, boolean);
+    method public void create(int, int);
+    method public void createBarrier(int, int, int, int...!);
+    method public void createHorizontalChain(int, int, int, int, int[]!, float[]!, int);
+    method public void createHorizontalChainRtl(int, int, int, int, int[]!, float[]!, int);
+    method public void createVerticalChain(int, int, int, int, int[]!, float[]!, int);
+    method public void dump(androidx.constraintlayout.motion.widget.MotionScene!, int...!);
+    method public boolean getApplyElevation(int);
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! getConstraint(int);
+    method public java.util.HashMap! getCustomAttributeSet();
+    method public int getHeight(int);
+    method public int[]! getKnownIds();
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! getParameters(int);
+    method public int[]! getReferencedIds(int);
+    method public String![]! getStateLabels();
+    method public int getVisibility(int);
+    method public int getVisibilityMode(int);
+    method public int getWidth(int);
+    method public boolean isForceId();
+    method public boolean isValidateOnParse();
+    method public void load(android.content.Context!, int);
+    method public void load(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public boolean matchesLabels(java.lang.String!...!);
+    method public void parseColorAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseFloatAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseIntAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseStringAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void readFallback(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void readFallback(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void removeAttribute(String!);
+    method public void removeFromHorizontalChain(int);
+    method public void removeFromVerticalChain(int);
+    method public void setAlpha(int, float);
+    method public void setApplyElevation(int, boolean);
+    method public void setBarrierType(int, int);
+    method public void setColorValue(int, String!, int);
+    method public void setDimensionRatio(int, String!);
+    method public void setEditorAbsoluteX(int, int);
+    method public void setEditorAbsoluteY(int, int);
+    method public void setElevation(int, float);
+    method public void setFloatValue(int, String!, float);
+    method public void setForceId(boolean);
+    method public void setGoneMargin(int, int, int);
+    method public void setGuidelineBegin(int, int);
+    method public void setGuidelineEnd(int, int);
+    method public void setGuidelinePercent(int, float);
+    method public void setHorizontalBias(int, float);
+    method public void setHorizontalChainStyle(int, int);
+    method public void setHorizontalWeight(int, float);
+    method public void setIntValue(int, String!, int);
+    method public void setLayoutWrapBehavior(int, int);
+    method public void setMargin(int, int, int);
+    method public void setReferencedIds(int, int...!);
+    method public void setRotation(int, float);
+    method public void setRotationX(int, float);
+    method public void setRotationY(int, float);
+    method public void setScaleX(int, float);
+    method public void setScaleY(int, float);
+    method public void setStateLabels(String!);
+    method public void setStateLabelsList(java.lang.String!...!);
+    method public void setStringValue(int, String!, String!);
+    method public void setTransformPivot(int, float, float);
+    method public void setTransformPivotX(int, float);
+    method public void setTransformPivotY(int, float);
+    method public void setTranslation(int, float, float);
+    method public void setTranslationX(int, float);
+    method public void setTranslationY(int, float);
+    method public void setTranslationZ(int, float);
+    method public void setValidateOnParse(boolean);
+    method public void setVerticalBias(int, float);
+    method public void setVerticalChainStyle(int, int);
+    method public void setVerticalWeight(int, float);
+    method public void setVisibility(int, int);
+    method public void setVisibilityMode(int, int);
+    method public void writeState(java.io.Writer!, androidx.constraintlayout.widget.ConstraintLayout!, int) throws java.io.IOException;
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int CIRCLE_REFERENCE = 8; // 0x8
+    field public static final int END = 7; // 0x7
+    field public static final int GONE = 8; // 0x8
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int HORIZONTAL_GUIDELINE = 0; // 0x0
+    field public static final int INVISIBLE = 4; // 0x4
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VERTICAL_GUIDELINE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_IGNORE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_NORMAL = 0; // 0x0
+    field public static final int VISIBLE = 0; // 0x0
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+    field public String! derivedState;
+    field public String! mIdString;
+    field public int mRotate;
+  }
+
+  public static class ConstraintSet.Constraint {
+    ctor public ConstraintSet.Constraint();
+    method public void applyDelta(androidx.constraintlayout.widget.ConstraintSet.Constraint!);
+    method public void applyTo(androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! clone();
+    method public void printDelta(String!);
+    field public final androidx.constraintlayout.widget.ConstraintSet.Layout! layout;
+    field public java.util.HashMap! mCustomConstraints;
+    field public final androidx.constraintlayout.widget.ConstraintSet.Motion! motion;
+    field public final androidx.constraintlayout.widget.ConstraintSet.PropertySet! propertySet;
+    field public final androidx.constraintlayout.widget.ConstraintSet.Transform! transform;
+  }
+
+  public static class ConstraintSet.Layout {
+    ctor public ConstraintSet.Layout();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Layout!);
+    method public void dump(androidx.constraintlayout.motion.widget.MotionScene!, StringBuilder!);
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int UNSET_GONE_MARGIN = -2147483648; // 0x80000000
+    field public int baselineMargin;
+    field public int baselineToBaseline;
+    field public int baselineToBottom;
+    field public int baselineToTop;
+    field public int bottomMargin;
+    field public int bottomToBottom;
+    field public int bottomToTop;
+    field public float circleAngle;
+    field public int circleConstraint;
+    field public int circleRadius;
+    field public boolean constrainedHeight;
+    field public boolean constrainedWidth;
+    field public String! dimensionRatio;
+    field public int editorAbsoluteX;
+    field public int editorAbsoluteY;
+    field public int endMargin;
+    field public int endToEnd;
+    field public int endToStart;
+    field public int goneBaselineMargin;
+    field public int goneBottomMargin;
+    field public int goneEndMargin;
+    field public int goneLeftMargin;
+    field public int goneRightMargin;
+    field public int goneStartMargin;
+    field public int goneTopMargin;
+    field public int guideBegin;
+    field public int guideEnd;
+    field public float guidePercent;
+    field public boolean guidelineUseRtl;
+    field public int heightDefault;
+    field public int heightMax;
+    field public int heightMin;
+    field public float heightPercent;
+    field public float horizontalBias;
+    field public int horizontalChainStyle;
+    field public float horizontalWeight;
+    field public int leftMargin;
+    field public int leftToLeft;
+    field public int leftToRight;
+    field public boolean mApply;
+    field public boolean mBarrierAllowsGoneWidgets;
+    field public int mBarrierDirection;
+    field public int mBarrierMargin;
+    field public String! mConstraintTag;
+    field public int mHeight;
+    field public int mHelperType;
+    field public boolean mIsGuideline;
+    field public boolean mOverride;
+    field public String! mReferenceIdString;
+    field public int[]! mReferenceIds;
+    field public int mWidth;
+    field public int mWrapBehavior;
+    field public int orientation;
+    field public int rightMargin;
+    field public int rightToLeft;
+    field public int rightToRight;
+    field public int startMargin;
+    field public int startToEnd;
+    field public int startToStart;
+    field public int topMargin;
+    field public int topToBottom;
+    field public int topToTop;
+    field public float verticalBias;
+    field public int verticalChainStyle;
+    field public float verticalWeight;
+    field public int widthDefault;
+    field public int widthMax;
+    field public int widthMin;
+    field public float widthPercent;
+  }
+
+  public static class ConstraintSet.Motion {
+    ctor public ConstraintSet.Motion();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Motion!);
+    field public int mAnimateCircleAngleTo;
+    field public int mAnimateRelativeTo;
+    field public boolean mApply;
+    field public int mDrawPath;
+    field public float mMotionStagger;
+    field public int mPathMotionArc;
+    field public float mPathRotate;
+    field public int mPolarRelativeTo;
+    field public int mQuantizeInterpolatorID;
+    field public String! mQuantizeInterpolatorString;
+    field public int mQuantizeInterpolatorType;
+    field public float mQuantizeMotionPhase;
+    field public int mQuantizeMotionSteps;
+    field public String! mTransitionEasing;
+  }
+
+  public static class ConstraintSet.PropertySet {
+    ctor public ConstraintSet.PropertySet();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.PropertySet!);
+    field public float alpha;
+    field public boolean mApply;
+    field public float mProgress;
+    field public int mVisibilityMode;
+    field public int visibility;
+  }
+
+  public static class ConstraintSet.Transform {
+    ctor public ConstraintSet.Transform();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Transform!);
+    field public boolean applyElevation;
+    field public float elevation;
+    field public boolean mApply;
+    field public float rotation;
+    field public float rotationX;
+    field public float rotationY;
+    field public float scaleX;
+    field public float scaleY;
+    field public int transformPivotTarget;
+    field public float transformPivotX;
+    field public float transformPivotY;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+  }
+
+  public class Constraints extends android.view.ViewGroup {
+    ctor public Constraints(android.content.Context!);
+    ctor public Constraints(android.content.Context!, android.util.AttributeSet!);
+    ctor public Constraints(android.content.Context!, android.util.AttributeSet!, int);
+    method protected androidx.constraintlayout.widget.Constraints.LayoutParams! generateDefaultLayoutParams();
+    method public androidx.constraintlayout.widget.Constraints.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet();
+    field public static final String TAG = "Constraints";
+  }
+
+  public static class Constraints.LayoutParams extends androidx.constraintlayout.widget.ConstraintLayout.LayoutParams {
+    ctor public Constraints.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public Constraints.LayoutParams(androidx.constraintlayout.widget.Constraints.LayoutParams!);
+    ctor public Constraints.LayoutParams(int, int);
+    field public float alpha;
+    field public boolean applyElevation;
+    field public float elevation;
+    field public float rotation;
+    field public float rotationX;
+    field public float rotationY;
+    field public float scaleX;
+    field public float scaleY;
+    field public float transformPivotX;
+    field public float transformPivotY;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+  }
+
+  public abstract class ConstraintsChangedListener {
+    ctor public ConstraintsChangedListener();
+    method public void postLayoutChange(int, int);
+    method public void preLayoutChange(int, int);
+  }
+
+  public class Group extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Group(android.content.Context!);
+    ctor public Group(android.content.Context!, android.util.AttributeSet!);
+    ctor public Group(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onAttachedToWindow();
+  }
+
+  public class Guideline extends android.view.View {
+    ctor public Guideline(android.content.Context!);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public void setFilterRedundantCalls(boolean);
+    method public void setGuidelineBegin(int);
+    method public void setGuidelineEnd(int);
+    method public void setGuidelinePercent(float);
+  }
+
+  public class Placeholder extends android.view.View {
+    ctor public Placeholder(android.content.Context!);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public android.view.View! getContent();
+    method public int getEmptyVisibility();
+    method public void onDraw(android.graphics.Canvas);
+    method public void setContentId(int);
+    method public void setEmptyVisibility(int);
+    method public void updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+  }
+
+  public class ReactiveGuide extends android.view.View implements androidx.constraintlayout.widget.SharedValues.SharedValuesListener {
+    ctor public ReactiveGuide(android.content.Context!);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public int getApplyToConstraintSetId();
+    method public int getAttributeId();
+    method public boolean isAnimatingChange();
+    method public void onNewValue(int, int, int);
+    method public void setAnimateChange(boolean);
+    method public void setApplyToConstraintSetId(int);
+    method public void setAttributeId(int);
+    method public void setGuidelineBegin(int);
+    method public void setGuidelineEnd(int);
+    method public void setGuidelinePercent(float);
+  }
+
+  public class SharedValues {
+    ctor public SharedValues();
+    method public void addListener(int, androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    method public void clearListeners();
+    method public void fireNewValue(int, int);
+    method public int getValue(int);
+    method public void removeListener(androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    method public void removeListener(int, androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public static interface SharedValues.SharedValuesListener {
+    method public void onNewValue(int, int, int);
+  }
+
+  public class StateSet {
+    ctor public StateSet(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public int convertToConstraintSet(int, int, float, float);
+    method public boolean needsToChange(int, float, float);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public int stateGetConstraintID(int, int, int);
+    method public int updateConstraints(int, int, float, float);
+    field public static final String TAG = "ConstraintLayoutStates";
+  }
+
+  public abstract class VirtualLayout extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public VirtualLayout(android.content.Context!);
+    ctor public VirtualLayout(android.content.Context!, android.util.AttributeSet!);
+    ctor public VirtualLayout(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onAttachedToWindow();
+    method public void onMeasure(androidx.constraintlayout.core.widgets.VirtualLayout!, int, int);
+  }
+
+}
+
diff --git a/constraintlayout/constraintlayout/api/res-2.2.0-beta01.txt b/constraintlayout/constraintlayout/api/res-2.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/constraintlayout/constraintlayout/api/res-2.2.0-beta01.txt
diff --git a/constraintlayout/constraintlayout/api/restricted_2.2.0-beta01.txt b/constraintlayout/constraintlayout/api/restricted_2.2.0-beta01.txt
new file mode 100644
index 0000000..2d187a8
--- /dev/null
+++ b/constraintlayout/constraintlayout/api/restricted_2.2.0-beta01.txt
@@ -0,0 +1,1714 @@
+// Signature format: 4.0
+package androidx.constraintlayout.helper.widget {
+
+  public class Carousel extends androidx.constraintlayout.motion.widget.MotionHelper {
+    ctor public Carousel(android.content.Context!);
+    ctor public Carousel(android.content.Context!, android.util.AttributeSet!);
+    ctor public Carousel(android.content.Context!, android.util.AttributeSet!, int);
+    method public int getCount();
+    method public int getCurrentIndex();
+    method public boolean isInfinite();
+    method public void jumpToIndex(int);
+    method public void refresh();
+    method public void setAdapter(androidx.constraintlayout.helper.widget.Carousel.Adapter!);
+    method public void setInfinite(boolean);
+    method public void transitionToIndex(int, int);
+    field public static final int TOUCH_UP_CARRY_ON = 2; // 0x2
+    field public static final int TOUCH_UP_IMMEDIATE_STOP = 1; // 0x1
+  }
+
+  public static interface Carousel.Adapter {
+    method public int count();
+    method public void onNewItem(int);
+    method public void populate(android.view.View!, int);
+  }
+
+  public class CircularFlow extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public CircularFlow(android.content.Context!);
+    ctor public CircularFlow(android.content.Context!, android.util.AttributeSet!);
+    ctor public CircularFlow(android.content.Context!, android.util.AttributeSet!, int);
+    method public void addViewToCircularFlow(android.view.View!, int, float);
+    method public float[]! getAngles();
+    method public int[]! getRadius();
+    method public boolean isUpdatable(android.view.View!);
+    method public void setDefaultAngle(float);
+    method public void setDefaultRadius(int);
+    method public void updateAngle(android.view.View!, float);
+    method public void updateRadius(android.view.View!, int);
+    method public void updateReference(android.view.View!, int, float);
+  }
+
+  public class Flow extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public Flow(android.content.Context!);
+    ctor public Flow(android.content.Context!, android.util.AttributeSet!);
+    ctor public Flow(android.content.Context!, android.util.AttributeSet!, int);
+    method public void setFirstHorizontalBias(float);
+    method public void setFirstHorizontalStyle(int);
+    method public void setFirstVerticalBias(float);
+    method public void setFirstVerticalStyle(int);
+    method public void setHorizontalAlign(int);
+    method public void setHorizontalBias(float);
+    method public void setHorizontalGap(int);
+    method public void setHorizontalStyle(int);
+    method public void setLastHorizontalBias(float);
+    method public void setLastHorizontalStyle(int);
+    method public void setLastVerticalBias(float);
+    method public void setLastVerticalStyle(int);
+    method public void setMaxElementsWrap(int);
+    method public void setOrientation(int);
+    method public void setPadding(int);
+    method public void setPaddingBottom(int);
+    method public void setPaddingLeft(int);
+    method public void setPaddingRight(int);
+    method public void setPaddingTop(int);
+    method public void setVerticalAlign(int);
+    method public void setVerticalBias(float);
+    method public void setVerticalGap(int);
+    method public void setVerticalStyle(int);
+    method public void setWrapMode(int);
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int HORIZONTAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int HORIZONTAL_ALIGN_END = 1; // 0x1
+    field public static final int HORIZONTAL_ALIGN_START = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_BASELINE = 3; // 0x3
+    field public static final int VERTICAL_ALIGN_BOTTOM = 1; // 0x1
+    field public static final int VERTICAL_ALIGN_CENTER = 2; // 0x2
+    field public static final int VERTICAL_ALIGN_TOP = 0; // 0x0
+    field public static final int WRAP_ALIGNED = 2; // 0x2
+    field public static final int WRAP_CHAIN = 1; // 0x1
+    field public static final int WRAP_NONE = 0; // 0x0
+  }
+
+  public class Grid extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public Grid(android.content.Context!);
+    ctor public Grid(android.content.Context!, android.util.AttributeSet!);
+    ctor public Grid(android.content.Context!, android.util.AttributeSet!, int);
+    method public String! getColumnWeights();
+    method public int getColumns();
+    method public float getHorizontalGaps();
+    method public int getOrientation();
+    method public String! getRowWeights();
+    method public int getRows();
+    method public String! getSkips();
+    method public String! getSpans();
+    method public float getVerticalGaps();
+    method public void setColumnWeights(String!);
+    method public void setColumns(int);
+    method public void setHorizontalGaps(float);
+    method public void setOrientation(int);
+    method public void setRowWeights(String!);
+    method public void setRows(int);
+    method public void setSkips(String!);
+    method public void setSpans(CharSequence!);
+    method public void setVerticalGaps(float);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class Layer extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Layer(android.content.Context!);
+    ctor public Layer(android.content.Context!, android.util.AttributeSet!);
+    ctor public Layer(android.content.Context!, android.util.AttributeSet!, int);
+    method protected void calcCenters();
+    field protected float mComputedCenterX;
+    field protected float mComputedCenterY;
+    field protected float mComputedMaxX;
+    field protected float mComputedMaxY;
+    field protected float mComputedMinX;
+    field protected float mComputedMinY;
+  }
+
+  public class MotionEffect extends androidx.constraintlayout.motion.widget.MotionHelper {
+    ctor public MotionEffect(android.content.Context!);
+    ctor public MotionEffect(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionEffect(android.content.Context!, android.util.AttributeSet!, int);
+    field public static final int AUTO = -1; // 0xffffffff
+    field public static final int EAST = 2; // 0x2
+    field public static final int NORTH = 0; // 0x0
+    field public static final int SOUTH = 1; // 0x1
+    field public static final String TAG = "FadeMove";
+    field public static final int WEST = 3; // 0x3
+  }
+
+  public class MotionPlaceholder extends androidx.constraintlayout.widget.VirtualLayout {
+    ctor public MotionPlaceholder(android.content.Context!);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public MotionPlaceholder(android.content.Context!, android.util.AttributeSet!, int, int);
+  }
+
+}
+
+package androidx.constraintlayout.motion.utils {
+
+  public class CustomSupport {
+    ctor public CustomSupport();
+    method public static void setInterpolatedValue(androidx.constraintlayout.widget.ConstraintAttribute!, android.view.View!, float[]!);
+  }
+
+  public class StopLogic extends androidx.constraintlayout.motion.widget.MotionInterpolator {
+    ctor public StopLogic();
+    method public void config(float, float, float, float, float, float);
+    method public String! debug(String!, float);
+    method public float getInterpolation(float);
+    method public float getVelocity();
+    method public float getVelocity(float);
+    method public boolean isStopped();
+    method public void springConfig(float, float, float, float, float, float, float, int);
+  }
+
+  public abstract class ViewOscillator extends androidx.constraintlayout.core.motion.utils.KeyCycleOscillator {
+    ctor public ViewOscillator();
+    method public static androidx.constraintlayout.motion.utils.ViewOscillator! makeSpline(String!);
+    method public abstract void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewOscillator.PathRotateSet extends androidx.constraintlayout.motion.utils.ViewOscillator {
+    ctor public ViewOscillator.PathRotateSet();
+    method public void setPathRotate(android.view.View!, float, double, double);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public abstract class ViewSpline extends androidx.constraintlayout.core.motion.utils.SplineSet {
+    ctor public ViewSpline();
+    method public static androidx.constraintlayout.motion.utils.ViewSpline! makeCustomSpline(String!, android.util.SparseArray!);
+    method public static androidx.constraintlayout.motion.utils.ViewSpline! makeSpline(String!);
+    method public abstract void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewSpline.CustomSet extends androidx.constraintlayout.motion.utils.ViewSpline {
+    ctor public ViewSpline.CustomSet(String!, android.util.SparseArray!);
+    method public void setPoint(int, androidx.constraintlayout.widget.ConstraintAttribute!);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public static class ViewSpline.PathRotate extends androidx.constraintlayout.motion.utils.ViewSpline {
+    ctor public ViewSpline.PathRotate();
+    method public void setPathRotate(android.view.View!, float, double, double);
+    method public void setProperty(android.view.View!, float);
+  }
+
+  public class ViewState {
+    ctor public ViewState();
+    method public void getState(android.view.View!);
+    method public int height();
+    method public int width();
+    field public int bottom;
+    field public int left;
+    field public int right;
+    field public float rotation;
+    field public int top;
+  }
+
+  public abstract class ViewTimeCycle extends androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet {
+    ctor public ViewTimeCycle();
+    method public float get(float, long, android.view.View!, androidx.constraintlayout.core.motion.utils.KeyCache!);
+    method public static androidx.constraintlayout.motion.utils.ViewTimeCycle! makeCustomSpline(String!, android.util.SparseArray!);
+    method public static androidx.constraintlayout.motion.utils.ViewTimeCycle! makeSpline(String!, long);
+    method public abstract boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class ViewTimeCycle.CustomSet extends androidx.constraintlayout.motion.utils.ViewTimeCycle {
+    ctor public ViewTimeCycle.CustomSet(String!, android.util.SparseArray!);
+    method public void setPoint(int, androidx.constraintlayout.widget.ConstraintAttribute!, float, int, float);
+    method public boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+  public static class ViewTimeCycle.PathRotate extends androidx.constraintlayout.motion.utils.ViewTimeCycle {
+    ctor public ViewTimeCycle.PathRotate();
+    method public boolean setPathRotate(android.view.View!, androidx.constraintlayout.core.motion.utils.KeyCache!, float, long, double, double);
+    method public boolean setProperty(android.view.View!, float, long, androidx.constraintlayout.core.motion.utils.KeyCache!);
+  }
+
+}
+
+package androidx.constraintlayout.motion.widget {
+
+  public interface Animatable {
+    method public float getProgress();
+    method public void setProgress(float);
+  }
+
+  public interface CustomFloatAttributes {
+    method public float get(String!);
+    method public String![]! getListOfAttributes();
+    method public void set(String!, float);
+  }
+
+  public class Debug {
+    ctor public Debug();
+    method public static void dumpLayoutParams(android.view.ViewGroup!, String!);
+    method public static void dumpLayoutParams(android.view.ViewGroup.LayoutParams!, String!);
+    method public static void dumpPoc(Object!);
+    method public static String! getActionType(android.view.MotionEvent!);
+    method public static String! getCallFrom(int);
+    method public static String! getLoc();
+    method public static String! getLocation();
+    method public static String! getLocation2();
+    method public static String! getName(android.content.Context!, int);
+    method public static String! getName(android.content.Context!, int[]!);
+    method public static String! getName(android.view.View!);
+    method public static String! getState(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public static String! getState(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public static void logStack(String!, String!, int);
+    method public static void printStack(String!, int);
+  }
+
+  public class DesignTool {
+    ctor public DesignTool(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public int designAccess(int, String!, Object!, float[]!, int, float[]!, int);
+    method public void disableAutoTransition(boolean);
+    method public void dumpConstraintSet(String!);
+    method public int getAnimationKeyFrames(Object!, float[]!);
+    method public int getAnimationPath(Object!, float[]!, int);
+    method public void getAnimationRectangles(Object!, float[]!);
+    method public String! getEndState();
+    method public int getKeyFrameInfo(Object!, int, int[]!);
+    method public float getKeyFramePosition(Object!, int, float, float);
+    method public int getKeyFramePositions(Object!, int[]!, float[]!);
+    method public Object! getKeyframe(int, int, int);
+    method public Object! getKeyframe(Object!, int, int);
+    method public Object! getKeyframeAtLocation(Object!, float, float);
+    method public Boolean! getPositionKeyframe(Object!, Object!, float, float, String![]!, float[]!);
+    method public float getProgress();
+    method public String! getStartState();
+    method public String! getState();
+    method public long getTransitionTimeMs();
+    method public boolean isInTransition();
+    method public void setAttributes(int, String!, Object!, Object!);
+    method public void setKeyFrame(Object!, int, String!, Object!);
+    method public boolean setKeyFramePosition(Object!, int, int, float, float);
+    method public void setKeyframe(Object!, String!, Object!);
+    method public void setState(String!);
+    method public void setToolPosition(float);
+    method public void setTransition(String!, String!);
+    method public void setViewDebug(Object!, int);
+  }
+
+  public interface FloatLayout {
+    method public void layout(float, float, float, float);
+  }
+
+  public abstract class Key {
+    ctor public Key();
+    method public abstract void addValues(java.util.HashMap!);
+    method public abstract androidx.constraintlayout.motion.widget.Key! clone();
+    method public androidx.constraintlayout.motion.widget.Key! copy(androidx.constraintlayout.motion.widget.Key!);
+    method public int getFramePosition();
+    method public void setFramePosition(int);
+    method public void setInterpolation(java.util.HashMap!);
+    method public abstract void setValue(String!, Object!);
+    method public androidx.constraintlayout.motion.widget.Key! setViewId(int);
+    field public static final String ALPHA = "alpha";
+    field public static final String CURVEFIT = "curveFit";
+    field public static final String CUSTOM = "CUSTOM";
+    field public static final String ELEVATION = "elevation";
+    field public static final String MOTIONPROGRESS = "motionProgress";
+    field public static final String PIVOT_X = "transformPivotX";
+    field public static final String PIVOT_Y = "transformPivotY";
+    field public static final String PROGRESS = "progress";
+    field public static final String ROTATION = "rotation";
+    field public static final String ROTATION_X = "rotationX";
+    field public static final String ROTATION_Y = "rotationY";
+    field public static final String SCALE_X = "scaleX";
+    field public static final String SCALE_Y = "scaleY";
+    field public static final String TRANSITIONEASING = "transitionEasing";
+    field public static final String TRANSITION_PATH_ROTATE = "transitionPathRotate";
+    field public static final String TRANSLATION_X = "translationX";
+    field public static final String TRANSLATION_Y = "translationY";
+    field public static final String TRANSLATION_Z = "translationZ";
+    field public static int UNSET;
+    field public static final String VISIBILITY = "visibility";
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_VARIES_BY = "waveVariesBy";
+    field protected int mType;
+  }
+
+  public class KeyAttributes extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyAttributes();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 1; // 0x1
+  }
+
+  public class KeyCycle extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyCycle();
+    method public void addCycleValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public float getValue(String!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 4; // 0x4
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_PHASE = "wavePhase";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class KeyFrames {
+    ctor public KeyFrames();
+    ctor public KeyFrames(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void addAllFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public void addFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public void addKey(androidx.constraintlayout.motion.widget.Key!);
+    method public java.util.ArrayList! getKeyFramesForView(int);
+    method public java.util.Set! getKeys();
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public class KeyPosition extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyPosition();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public boolean intersects(int, int, android.graphics.RectF!, android.graphics.RectF!, float, float);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void positionAttributes(android.view.View!, android.graphics.RectF!, android.graphics.RectF!, float, float, String![]!, float[]!);
+    method public void setType(int);
+    method public void setValue(String!, Object!);
+    field public static final String DRAWPATH = "drawPath";
+    field public static final String PERCENT_HEIGHT = "percentHeight";
+    field public static final String PERCENT_WIDTH = "percentWidth";
+    field public static final String PERCENT_X = "percentX";
+    field public static final String PERCENT_Y = "percentY";
+    field public static final String SIZE_PERCENT = "sizePercent";
+    field public static final String TRANSITION_EASING = "transitionEasing";
+    field public static final int TYPE_AXIS = 3; // 0x3
+    field public static final int TYPE_CARTESIAN = 0; // 0x0
+    field public static final int TYPE_PATH = 1; // 0x1
+    field public static final int TYPE_SCREEN = 2; // 0x2
+  }
+
+  public class KeyTimeCycle extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyTimeCycle();
+    method public void addTimeValues(java.util.HashMap!);
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final int KEY_TYPE = 3; // 0x3
+    field public static final int SHAPE_BOUNCE = 6; // 0x6
+    field public static final int SHAPE_COS_WAVE = 5; // 0x5
+    field public static final int SHAPE_REVERSE_SAW_WAVE = 4; // 0x4
+    field public static final int SHAPE_SAW_WAVE = 3; // 0x3
+    field public static final int SHAPE_SIN_WAVE = 0; // 0x0
+    field public static final int SHAPE_SQUARE_WAVE = 1; // 0x1
+    field public static final int SHAPE_TRIANGLE_WAVE = 2; // 0x2
+    field public static final String WAVE_OFFSET = "waveOffset";
+    field public static final String WAVE_PERIOD = "wavePeriod";
+    field public static final String WAVE_SHAPE = "waveShape";
+  }
+
+  public class KeyTrigger extends androidx.constraintlayout.motion.widget.Key {
+    ctor public KeyTrigger();
+    method public void addValues(java.util.HashMap!);
+    method public androidx.constraintlayout.motion.widget.Key! clone();
+    method public void conditionallyFire(float, android.view.View!);
+    method public void getAttributeNames(java.util.HashSet!);
+    method public void load(android.content.Context!, android.util.AttributeSet!);
+    method public void setValue(String!, Object!);
+    field public static final String CROSS = "CROSS";
+    field public static final int KEY_TYPE = 5; // 0x5
+    field public static final String NEGATIVE_CROSS = "negativeCross";
+    field public static final String POSITIVE_CROSS = "positiveCross";
+    field public static final String POST_LAYOUT = "postLayout";
+    field public static final String TRIGGER_COLLISION_ID = "triggerCollisionId";
+    field public static final String TRIGGER_COLLISION_VIEW = "triggerCollisionView";
+    field public static final String TRIGGER_ID = "triggerID";
+    field public static final String TRIGGER_RECEIVER = "triggerReceiver";
+    field public static final String TRIGGER_SLACK = "triggerSlack";
+    field public static final String VIEW_TRANSITION_ON_CROSS = "viewTransitionOnCross";
+    field public static final String VIEW_TRANSITION_ON_NEGATIVE_CROSS = "viewTransitionOnNegativeCross";
+    field public static final String VIEW_TRANSITION_ON_POSITIVE_CROSS = "viewTransitionOnPositiveCross";
+  }
+
+  public class MotionController {
+    method public void addKey(androidx.constraintlayout.motion.widget.Key!);
+    method public int getAnimateRelativeTo();
+    method public void getCenter(double, float[]!, float[]!);
+    method public float getCenterX();
+    method public float getCenterY();
+    method public int getDrawPath();
+    method public float getFinalHeight();
+    method public float getFinalWidth();
+    method public float getFinalX();
+    method public float getFinalY();
+    method public int getKeyFrameInfo(int, int[]!);
+    method public int getKeyFramePositions(int[]!, float[]!);
+    method public float getStartHeight();
+    method public float getStartWidth();
+    method public float getStartX();
+    method public float getStartY();
+    method public int getTransformPivotTarget();
+    method public android.view.View! getView();
+    method public void remeasure();
+    method public void setDrawPath(int);
+    method public void setPathMotionArc(int);
+    method public void setStartState(androidx.constraintlayout.motion.utils.ViewState!, android.view.View!, int, int, int);
+    method public void setTransformPivotTarget(int);
+    method public void setView(android.view.View!);
+    method public void setup(int, int, float, long);
+    method public void setupRelative(androidx.constraintlayout.motion.widget.MotionController!);
+    field public static final int DRAW_PATH_AS_CONFIGURED = 4; // 0x4
+    field public static final int DRAW_PATH_BASIC = 1; // 0x1
+    field public static final int DRAW_PATH_CARTESIAN = 3; // 0x3
+    field public static final int DRAW_PATH_NONE = 0; // 0x0
+    field public static final int DRAW_PATH_RECTANGLE = 5; // 0x5
+    field public static final int DRAW_PATH_RELATIVE = 2; // 0x2
+    field public static final int DRAW_PATH_SCREEN = 6; // 0x6
+    field public static final int HORIZONTAL_PATH_X = 2; // 0x2
+    field public static final int HORIZONTAL_PATH_Y = 3; // 0x3
+    field public static final int PATH_PERCENT = 0; // 0x0
+    field public static final int PATH_PERPENDICULAR = 1; // 0x1
+    field public static final int ROTATION_LEFT = 2; // 0x2
+    field public static final int ROTATION_RIGHT = 1; // 0x1
+    field public static final int VERTICAL_PATH_X = 4; // 0x4
+    field public static final int VERTICAL_PATH_Y = 5; // 0x5
+  }
+
+  public class MotionHelper extends androidx.constraintlayout.widget.ConstraintHelper implements androidx.constraintlayout.motion.widget.MotionHelperInterface {
+    ctor public MotionHelper(android.content.Context!);
+    ctor public MotionHelper(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionHelper(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getProgress();
+    method public boolean isDecorator();
+    method public boolean isUseOnHide();
+    method public boolean isUsedOnShow();
+    method public void onFinishedMotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void onPostDraw(android.graphics.Canvas!);
+    method public void onPreDraw(android.graphics.Canvas!);
+    method public void onPreSetup(androidx.constraintlayout.motion.widget.MotionLayout!, java.util.HashMap!);
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+    method public void setProgress(android.view.View!, float);
+    method public void setProgress(float);
+    field protected android.view.View![]! views;
+  }
+
+  public interface MotionHelperInterface extends androidx.constraintlayout.motion.widget.Animatable androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener {
+    method public boolean isDecorator();
+    method public boolean isUseOnHide();
+    method public boolean isUsedOnShow();
+    method public void onFinishedMotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void onPostDraw(android.graphics.Canvas!);
+    method public void onPreDraw(android.graphics.Canvas!);
+    method public void onPreSetup(androidx.constraintlayout.motion.widget.MotionLayout!, java.util.HashMap!);
+  }
+
+  public abstract class MotionInterpolator implements android.view.animation.Interpolator {
+    ctor public MotionInterpolator();
+    method public abstract float getVelocity();
+  }
+
+  public class MotionLayout extends androidx.constraintlayout.widget.ConstraintLayout implements androidx.core.view.NestedScrollingParent3 {
+    ctor public MotionLayout(android.content.Context);
+    ctor public MotionLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public MotionLayout(android.content.Context, android.util.AttributeSet?, int);
+    method public void addTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public boolean applyViewTransition(int, androidx.constraintlayout.motion.widget.MotionController!);
+    method public androidx.constraintlayout.widget.ConstraintSet! cloneConstraintSet(int);
+    method public void enableTransition(int, boolean);
+    method public void enableViewTransition(int, boolean);
+    method protected void fireTransitionCompleted();
+    method public void fireTrigger(int, boolean, float);
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet(int);
+    method @IdRes public int[]! getConstraintSetIds();
+    method public int getCurrentState();
+    method public java.util.ArrayList! getDefinedTransitions();
+    method public androidx.constraintlayout.motion.widget.DesignTool! getDesignTool();
+    method public int getEndState();
+    method public int[]! getMatchingConstraintSetIds(java.lang.String!...!);
+    method protected long getNanoTime();
+    method public float getProgress();
+    method public androidx.constraintlayout.motion.widget.MotionScene! getScene();
+    method public int getStartState();
+    method public float getTargetPosition();
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! getTransition(int);
+    method public android.os.Bundle! getTransitionState();
+    method public long getTransitionTimeMs();
+    method public float getVelocity();
+    method public void getViewVelocity(android.view.View!, float, float, float[]!, int);
+    method public boolean isDelayedApplicationOfInitialState();
+    method public boolean isInRotation();
+    method public boolean isInteractionEnabled();
+    method public boolean isViewTransitionEnabled(int);
+    method public void jumpToState(int);
+    method protected androidx.constraintlayout.motion.widget.MotionLayout.MotionTracker! obtainVelocityTracker();
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]!);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method @Deprecated public void rebuildMotion();
+    method public void rebuildScene();
+    method public boolean removeTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public void rotateTo(int, int);
+    method public void scheduleTransitionTo(int);
+    method public void setDebugMode(int);
+    method public void setDelayedApplicationOfInitialState(boolean);
+    method public void setInteractionEnabled(boolean);
+    method public void setInterpolatedProgress(float);
+    method public void setOnHide(float);
+    method public void setOnShow(float);
+    method public void setProgress(float);
+    method public void setProgress(float, float);
+    method public void setScene(androidx.constraintlayout.motion.widget.MotionScene!);
+    method protected void setTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void setTransition(int);
+    method public void setTransition(int, int);
+    method public void setTransitionDuration(int);
+    method public void setTransitionListener(androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener!);
+    method public void setTransitionState(android.os.Bundle!);
+    method public void touchAnimateTo(int, float, float);
+    method public void touchSpringTo(float, float);
+    method public void transitionToEnd();
+    method public void transitionToEnd(Runnable!);
+    method public void transitionToStart();
+    method public void transitionToStart(Runnable!);
+    method public void transitionToState(int);
+    method public void transitionToState(int, int);
+    method public void transitionToState(int, int, int);
+    method public void transitionToState(int, int, int, int);
+    method public void updateState();
+    method public void updateState(int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public void updateStateAnimate(int, androidx.constraintlayout.widget.ConstraintSet!, int);
+    method public void viewTransition(int, android.view.View!...!);
+    field public static final int DEBUG_SHOW_NONE = 0; // 0x0
+    field public static final int DEBUG_SHOW_PATH = 2; // 0x2
+    field public static final int DEBUG_SHOW_PROGRESS = 1; // 0x1
+    field public static boolean IS_IN_EDIT_MODE;
+    field public static final int TOUCH_UP_COMPLETE = 0; // 0x0
+    field public static final int TOUCH_UP_COMPLETE_TO_END = 2; // 0x2
+    field public static final int TOUCH_UP_COMPLETE_TO_START = 1; // 0x1
+    field public static final int TOUCH_UP_DECELERATE = 4; // 0x4
+    field public static final int TOUCH_UP_DECELERATE_AND_COMPLETE = 5; // 0x5
+    field public static final int TOUCH_UP_NEVER_TO_END = 7; // 0x7
+    field public static final int TOUCH_UP_NEVER_TO_START = 6; // 0x6
+    field public static final int TOUCH_UP_STOP = 3; // 0x3
+    field public static final int VELOCITY_LAYOUT = 1; // 0x1
+    field public static final int VELOCITY_POST_LAYOUT = 0; // 0x0
+    field public static final int VELOCITY_STATIC_LAYOUT = 3; // 0x3
+    field public static final int VELOCITY_STATIC_POST_LAYOUT = 2; // 0x2
+    field protected boolean mMeasureDuringTransition;
+  }
+
+  protected static interface MotionLayout.MotionTracker {
+    method public void addMovement(android.view.MotionEvent!);
+    method public void clear();
+    method public void computeCurrentVelocity(int);
+    method public void computeCurrentVelocity(int, float);
+    method public float getXVelocity();
+    method public float getXVelocity(int);
+    method public float getYVelocity();
+    method public float getYVelocity(int);
+    method public void recycle();
+  }
+
+  public static interface MotionLayout.TransitionListener {
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+  }
+
+  public class MotionScene {
+    ctor public MotionScene(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void addOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void addTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public boolean applyViewTransition(int, androidx.constraintlayout.motion.widget.MotionController!);
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! bestTransitionFor(int, float, float, android.view.MotionEvent!);
+    method public void disableAutoTransition(boolean);
+    method public void enableViewTransition(int, boolean);
+    method public int gatPathMotionArc();
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet(android.content.Context!, String!);
+    method public int[]! getConstraintSetIds();
+    method public java.util.ArrayList! getDefinedTransitions();
+    method public int getDuration();
+    method public android.view.animation.Interpolator! getInterpolator();
+    method public void getKeyFrames(androidx.constraintlayout.motion.widget.MotionController!);
+    method public int[]! getMatchingStateLabels(java.lang.String!...!);
+    method public float getPathPercent(android.view.View!, int);
+    method public float getStaggered();
+    method public androidx.constraintlayout.motion.widget.MotionScene.Transition! getTransitionById(int);
+    method public java.util.List! getTransitionsWithState(int);
+    method public boolean isViewTransitionEnabled(int);
+    method public int lookUpConstraintId(String!);
+    method public String! lookUpConstraintName(int);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void removeTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void setConstraintSet(int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public void setDuration(int);
+    method public void setKeyframe(android.view.View!, int, String!, Object!);
+    method public void setRtl(boolean);
+    method public void setTransition(androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public static String! stripID(String!);
+    method public boolean validateLayout(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void viewTransition(int, android.view.View!...!);
+    field public static final int LAYOUT_CALL_MEASURE = 2; // 0x2
+    field public static final int LAYOUT_HONOR_REQUEST = 1; // 0x1
+    field public static final int LAYOUT_IGNORE_REQUEST = 0; // 0x0
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public static class MotionScene.Transition {
+    ctor public MotionScene.Transition(int, androidx.constraintlayout.motion.widget.MotionScene!, int, int);
+    method public void addKeyFrame(androidx.constraintlayout.motion.widget.KeyFrames!);
+    method public void addOnClick(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void addOnClick(int, int);
+    method public String! debugString(android.content.Context!);
+    method public int getAutoTransition();
+    method public int getDuration();
+    method public int getEndConstraintSetId();
+    method public int getId();
+    method public java.util.List! getKeyFrameList();
+    method public int getLayoutDuringTransition();
+    method public java.util.List! getOnClickList();
+    method public int getPathMotionArc();
+    method public float getStagger();
+    method public int getStartConstraintSetId();
+    method public androidx.constraintlayout.motion.widget.TouchResponse! getTouchResponse();
+    method public boolean isEnabled();
+    method public boolean isTransitionFlag(int);
+    method public void removeOnClick(int);
+    method public void setAutoTransition(int);
+    method public void setDuration(int);
+    method public void setEnabled(boolean);
+    method public void setInterpolatorInfo(int, String!, int);
+    method public void setLayoutDuringTransition(int);
+    method public void setOnSwipe(androidx.constraintlayout.motion.widget.OnSwipe!);
+    method public void setOnTouchUp(int);
+    method public void setPathMotionArc(int);
+    method public void setStagger(float);
+    method public void setTransitionFlag(int);
+    field public static final int AUTO_ANIMATE_TO_END = 4; // 0x4
+    field public static final int AUTO_ANIMATE_TO_START = 3; // 0x3
+    field public static final int AUTO_JUMP_TO_END = 2; // 0x2
+    field public static final int AUTO_JUMP_TO_START = 1; // 0x1
+    field public static final int AUTO_NONE = 0; // 0x0
+    field public static final int INTERPOLATE_ANTICIPATE = 6; // 0x6
+    field public static final int INTERPOLATE_BOUNCE = 4; // 0x4
+    field public static final int INTERPOLATE_EASE_IN = 1; // 0x1
+    field public static final int INTERPOLATE_EASE_IN_OUT = 0; // 0x0
+    field public static final int INTERPOLATE_EASE_OUT = 2; // 0x2
+    field public static final int INTERPOLATE_LINEAR = 3; // 0x3
+    field public static final int INTERPOLATE_OVERSHOOT = 5; // 0x5
+    field public static final int INTERPOLATE_REFERENCE_ID = -2; // 0xfffffffe
+    field public static final int INTERPOLATE_SPLINE_STRING = -1; // 0xffffffff
+  }
+
+  public static class MotionScene.Transition.TransitionOnClick implements android.view.View.OnClickListener {
+    ctor public MotionScene.Transition.TransitionOnClick(android.content.Context!, androidx.constraintlayout.motion.widget.MotionScene.Transition!, org.xmlpull.v1.XmlPullParser!);
+    ctor public MotionScene.Transition.TransitionOnClick(androidx.constraintlayout.motion.widget.MotionScene.Transition!, int, int);
+    method public void addOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!, int, androidx.constraintlayout.motion.widget.MotionScene.Transition!);
+    method public void onClick(android.view.View!);
+    method public void removeOnClickListeners(androidx.constraintlayout.motion.widget.MotionLayout!);
+    field public static final int ANIM_TOGGLE = 17; // 0x11
+    field public static final int ANIM_TO_END = 1; // 0x1
+    field public static final int ANIM_TO_START = 16; // 0x10
+    field public static final int JUMP_TO_END = 256; // 0x100
+    field public static final int JUMP_TO_START = 4096; // 0x1000
+  }
+
+  public class OnSwipe {
+    ctor public OnSwipe();
+    method public int getAutoCompleteMode();
+    method public int getDragDirection();
+    method public float getDragScale();
+    method public float getDragThreshold();
+    method public int getLimitBoundsTo();
+    method public float getMaxAcceleration();
+    method public float getMaxVelocity();
+    method public boolean getMoveWhenScrollAtTop();
+    method public int getNestedScrollFlags();
+    method public int getOnTouchUp();
+    method public int getRotationCenterId();
+    method public int getSpringBoundary();
+    method public float getSpringDamping();
+    method public float getSpringMass();
+    method public float getSpringStiffness();
+    method public float getSpringStopThreshold();
+    method public int getTouchAnchorId();
+    method public int getTouchAnchorSide();
+    method public int getTouchRegionId();
+    method public void setAutoCompleteMode(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragDirection(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragScale(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setDragThreshold(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setLimitBoundsTo(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMaxAcceleration(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMaxVelocity(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setMoveWhenScrollAtTop(boolean);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setNestedScrollFlags(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setOnTouchUp(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setRotateCenter(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringBoundary(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringDamping(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringMass(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringStiffness(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setSpringStopThreshold(float);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchAnchorId(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchAnchorSide(int);
+    method public androidx.constraintlayout.motion.widget.OnSwipe! setTouchRegionId(int);
+    field public static final int COMPLETE_MODE_CONTINUOUS_VELOCITY = 0; // 0x0
+    field public static final int COMPLETE_MODE_SPRING = 1; // 0x1
+    field public static final int DRAG_ANTICLOCKWISE = 7; // 0x7
+    field public static final int DRAG_CLOCKWISE = 6; // 0x6
+    field public static final int DRAG_DOWN = 1; // 0x1
+    field public static final int DRAG_END = 5; // 0x5
+    field public static final int DRAG_LEFT = 2; // 0x2
+    field public static final int DRAG_RIGHT = 3; // 0x3
+    field public static final int DRAG_START = 4; // 0x4
+    field public static final int DRAG_UP = 0; // 0x0
+    field public static final int FLAG_DISABLE_POST_SCROLL = 1; // 0x1
+    field public static final int FLAG_DISABLE_SCROLL = 2; // 0x2
+    field public static final int ON_UP_AUTOCOMPLETE = 0; // 0x0
+    field public static final int ON_UP_AUTOCOMPLETE_TO_END = 2; // 0x2
+    field public static final int ON_UP_AUTOCOMPLETE_TO_START = 1; // 0x1
+    field public static final int ON_UP_DECELERATE = 4; // 0x4
+    field public static final int ON_UP_DECELERATE_AND_COMPLETE = 5; // 0x5
+    field public static final int ON_UP_NEVER_TO_END = 7; // 0x7
+    field public static final int ON_UP_NEVER_TO_START = 6; // 0x6
+    field public static final int ON_UP_STOP = 3; // 0x3
+    field public static final int SIDE_BOTTOM = 3; // 0x3
+    field public static final int SIDE_END = 6; // 0x6
+    field public static final int SIDE_LEFT = 1; // 0x1
+    field public static final int SIDE_MIDDLE = 4; // 0x4
+    field public static final int SIDE_RIGHT = 2; // 0x2
+    field public static final int SIDE_START = 5; // 0x5
+    field public static final int SIDE_TOP = 0; // 0x0
+    field public static final int SPRING_BOUNDARY_BOUNCEBOTH = 3; // 0x3
+    field public static final int SPRING_BOUNDARY_BOUNCEEND = 2; // 0x2
+    field public static final int SPRING_BOUNDARY_BOUNCESTART = 1; // 0x1
+    field public static final int SPRING_BOUNDARY_OVERSHOOT = 0; // 0x0
+  }
+
+  public abstract class TransitionAdapter implements androidx.constraintlayout.motion.widget.MotionLayout.TransitionListener {
+    ctor public TransitionAdapter();
+    method public void onTransitionChange(androidx.constraintlayout.motion.widget.MotionLayout!, int, int, float);
+    method public void onTransitionCompleted(androidx.constraintlayout.motion.widget.MotionLayout!, int);
+    method public void onTransitionStarted(androidx.constraintlayout.motion.widget.MotionLayout!, int, int);
+    method public void onTransitionTrigger(androidx.constraintlayout.motion.widget.MotionLayout!, int, boolean, float);
+  }
+
+  public class TransitionBuilder {
+    ctor public TransitionBuilder();
+    method public static androidx.constraintlayout.motion.widget.MotionScene.Transition! buildTransition(androidx.constraintlayout.motion.widget.MotionScene!, int, int, androidx.constraintlayout.widget.ConstraintSet!, int, androidx.constraintlayout.widget.ConstraintSet!);
+    method public static void validate(androidx.constraintlayout.motion.widget.MotionLayout!);
+  }
+
+  public class ViewTransition {
+    method public int getSharedValue();
+    method public int getSharedValueCurrent();
+    method public int getSharedValueID();
+    method public int getStateTransition();
+    method public void setSharedValue(int);
+    method public void setSharedValueCurrent(int);
+    method public void setSharedValueID(int);
+    method public void setStateTransition(int);
+    field public static final String CONSTRAINT_OVERRIDE = "ConstraintOverride";
+    field public static final String CUSTOM_ATTRIBUTE = "CustomAttribute";
+    field public static final String CUSTOM_METHOD = "CustomMethod";
+    field public static final String KEY_FRAME_SET_TAG = "KeyFrameSet";
+    field public static final int ONSTATE_ACTION_DOWN = 1; // 0x1
+    field public static final int ONSTATE_ACTION_DOWN_UP = 3; // 0x3
+    field public static final int ONSTATE_ACTION_UP = 2; // 0x2
+    field public static final int ONSTATE_SHARED_VALUE_SET = 4; // 0x4
+    field public static final int ONSTATE_SHARED_VALUE_UNSET = 5; // 0x5
+    field public static final String VIEW_TRANSITION_TAG = "ViewTransition";
+  }
+
+  public class ViewTransitionController {
+    ctor public ViewTransitionController(androidx.constraintlayout.motion.widget.MotionLayout!);
+    method public void add(androidx.constraintlayout.motion.widget.ViewTransition!);
+  }
+
+}
+
+package androidx.constraintlayout.utils.widget {
+
+  public class ImageFilterButton extends androidx.appcompat.widget.AppCompatImageButton {
+    ctor public ImageFilterButton(android.content.Context!);
+    ctor public ImageFilterButton(android.content.Context!, android.util.AttributeSet!);
+    ctor public ImageFilterButton(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getContrast();
+    method public float getCrossfade();
+    method public float getImagePanX();
+    method public float getImagePanY();
+    method public float getImageRotate();
+    method public float getImageZoom();
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getSaturation();
+    method public float getWarmth();
+    method public void setAltImageResource(int);
+    method public void setBrightness(float);
+    method public void setContrast(float);
+    method public void setCrossfade(float);
+    method public void setImagePanX(float);
+    method public void setImagePanY(float);
+    method public void setImageRotate(float);
+    method public void setImageZoom(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setSaturation(float);
+    method public void setWarmth(float);
+  }
+
+  public class ImageFilterView extends androidx.appcompat.widget.AppCompatImageView {
+    ctor public ImageFilterView(android.content.Context!);
+    ctor public ImageFilterView(android.content.Context!, android.util.AttributeSet!);
+    ctor public ImageFilterView(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getBrightness();
+    method public float getContrast();
+    method public float getCrossfade();
+    method public float getImagePanX();
+    method public float getImagePanY();
+    method public float getImageRotate();
+    method public float getImageZoom();
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getSaturation();
+    method public float getWarmth();
+    method public void setAltImageDrawable(android.graphics.drawable.Drawable!);
+    method public void setAltImageResource(int);
+    method public void setBrightness(float);
+    method public void setContrast(float);
+    method public void setCrossfade(float);
+    method public void setImagePanX(float);
+    method public void setImagePanY(float);
+    method public void setImageRotate(float);
+    method public void setImageZoom(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setSaturation(float);
+    method public void setWarmth(float);
+  }
+
+  public class MockView extends android.view.View {
+    ctor public MockView(android.content.Context!);
+    ctor public MockView(android.content.Context!, android.util.AttributeSet!);
+    ctor public MockView(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onDraw(android.graphics.Canvas);
+    field protected String! mText;
+  }
+
+  public class MotionButton extends androidx.appcompat.widget.AppCompatButton {
+    ctor public MotionButton(android.content.Context!);
+    ctor public MotionButton(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionButton(android.content.Context!, android.util.AttributeSet!, int);
+    method public float getRound();
+    method public float getRoundPercent();
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+  }
+
+  public class MotionLabel extends android.view.View implements androidx.constraintlayout.motion.widget.FloatLayout {
+    ctor public MotionLabel(android.content.Context!);
+    ctor public MotionLabel(android.content.Context!, android.util.AttributeSet?);
+    ctor public MotionLabel(android.content.Context!, android.util.AttributeSet?, int);
+    method public float getRound();
+    method public float getRoundPercent();
+    method public float getScaleFromTextSize();
+    method public float getTextBackgroundPanX();
+    method public float getTextBackgroundPanY();
+    method public float getTextBackgroundRotate();
+    method public float getTextBackgroundZoom();
+    method public int getTextOutlineColor();
+    method public float getTextPanX();
+    method public float getTextPanY();
+    method public float getTextureHeight();
+    method public float getTextureWidth();
+    method public android.graphics.Typeface! getTypeface();
+    method public void layout(float, float, float, float);
+    method public void setGravity(int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRound(float);
+    method @RequiresApi(android.os.Build.VERSION_CODES.LOLLIPOP) public void setRoundPercent(float);
+    method public void setScaleFromTextSize(float);
+    method public void setText(CharSequence!);
+    method public void setTextBackgroundPanX(float);
+    method public void setTextBackgroundPanY(float);
+    method public void setTextBackgroundRotate(float);
+    method public void setTextBackgroundZoom(float);
+    method public void setTextFillColor(int);
+    method public void setTextOutlineColor(int);
+    method public void setTextOutlineThickness(float);
+    method public void setTextPanX(float);
+    method public void setTextPanY(float);
+    method public void setTextSize(float);
+    method public void setTextureHeight(float);
+    method public void setTextureWidth(float);
+    method public void setTypeface(android.graphics.Typeface!);
+  }
+
+  public class MotionTelltales extends androidx.constraintlayout.utils.widget.MockView {
+    ctor public MotionTelltales(android.content.Context!);
+    ctor public MotionTelltales(android.content.Context!, android.util.AttributeSet!);
+    ctor public MotionTelltales(android.content.Context!, android.util.AttributeSet!, int);
+    method public void setText(CharSequence!);
+  }
+
+}
+
+package androidx.constraintlayout.widget {
+
+  public class Barrier extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Barrier(android.content.Context!);
+    ctor public Barrier(android.content.Context!, android.util.AttributeSet!);
+    ctor public Barrier(android.content.Context!, android.util.AttributeSet!, int);
+    method @Deprecated public boolean allowsGoneWidget();
+    method public boolean getAllowsGoneWidget();
+    method public int getMargin();
+    method public int getType();
+    method public void setAllowsGoneWidget(boolean);
+    method public void setDpMargin(int);
+    method public void setMargin(int);
+    method public void setType(int);
+    field public static final int BOTTOM = 3; // 0x3
+    field public static final int END = 6; // 0x6
+    field public static final int LEFT = 0; // 0x0
+    field public static final int RIGHT = 1; // 0x1
+    field public static final int START = 5; // 0x5
+    field public static final int TOP = 2; // 0x2
+  }
+
+  public class ConstraintAttribute {
+    ctor public ConstraintAttribute(androidx.constraintlayout.widget.ConstraintAttribute!, Object!);
+    ctor public ConstraintAttribute(String!, androidx.constraintlayout.widget.ConstraintAttribute.AttributeType!);
+    ctor public ConstraintAttribute(String!, androidx.constraintlayout.widget.ConstraintAttribute.AttributeType!, Object!, boolean);
+    method public void applyCustom(android.view.View!);
+    method public boolean diff(androidx.constraintlayout.widget.ConstraintAttribute!);
+    method public static java.util.HashMap! extractAttributes(java.util.HashMap!, android.view.View!);
+    method public int getColorValue();
+    method public float getFloatValue();
+    method public int getIntegerValue();
+    method public String! getName();
+    method public String! getStringValue();
+    method public androidx.constraintlayout.widget.ConstraintAttribute.AttributeType! getType();
+    method public float getValueToInterpolate();
+    method public void getValuesToInterpolate(float[]!);
+    method public boolean isBooleanValue();
+    method public boolean isContinuous();
+    method public boolean isMethod();
+    method public int numberOfInterpolatedValues();
+    method public static void parse(android.content.Context!, org.xmlpull.v1.XmlPullParser!, java.util.HashMap!);
+    method public static void setAttributes(android.view.View!, java.util.HashMap!);
+    method public void setColorValue(int);
+    method public void setFloatValue(float);
+    method public void setIntValue(int);
+    method public void setStringValue(String!);
+    method public void setValue(float[]!);
+    method public void setValue(Object!);
+  }
+
+  public enum ConstraintAttribute.AttributeType {
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType BOOLEAN_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType COLOR_DRAWABLE_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType COLOR_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType DIMENSION_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType FLOAT_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType INT_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType REFERENCE_TYPE;
+    enum_constant public static final androidx.constraintlayout.widget.ConstraintAttribute.AttributeType STRING_TYPE;
+  }
+
+  public abstract class ConstraintHelper extends android.view.View {
+    ctor public ConstraintHelper(android.content.Context!);
+    ctor public ConstraintHelper(android.content.Context!, android.util.AttributeSet!);
+    ctor public ConstraintHelper(android.content.Context!, android.util.AttributeSet!, int);
+    method public void addView(android.view.View!);
+    method public void applyHelperParams();
+    method protected void applyLayoutFeatures();
+    method protected void applyLayoutFeatures(androidx.constraintlayout.widget.ConstraintLayout!);
+    method protected void applyLayoutFeaturesInConstraintSet(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public boolean containsId(int);
+    method public int[]! getReferencedIds();
+    method protected android.view.View![]! getViews(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public int indexFromId(int);
+    method protected void init(android.util.AttributeSet!);
+    method public static boolean isChildOfHelper(android.view.View!);
+    method public void loadParameters(androidx.constraintlayout.widget.ConstraintSet.Constraint!, androidx.constraintlayout.core.widgets.HelperWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method public void onDraw(android.graphics.Canvas);
+    method public int removeView(android.view.View!);
+    method public void resolveRtl(androidx.constraintlayout.core.widgets.ConstraintWidget!, boolean);
+    method protected void setIds(String!);
+    method protected void setReferenceTags(String!);
+    method public void setReferencedIds(int[]!);
+    method public void updatePostConstraints(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePostLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreDraw(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreLayout(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, androidx.constraintlayout.core.widgets.Helper!, android.util.SparseArray!);
+    method public void updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void validateParams();
+    field protected static final String CHILD_TAG = "CONSTRAINT_LAYOUT_HELPER_CHILD";
+    field protected int mCount;
+    field protected androidx.constraintlayout.core.widgets.Helper! mHelperWidget;
+    field protected int[]! mIds;
+    field protected java.util.HashMap! mMap;
+    field protected String! mReferenceIds;
+    field protected String! mReferenceTags;
+    field protected boolean mUseViewMeasure;
+    field protected android.content.Context! myContext;
+  }
+
+  public class ConstraintLayout extends android.view.ViewGroup {
+    ctor public ConstraintLayout(android.content.Context);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?, int);
+    ctor public ConstraintLayout(android.content.Context, android.util.AttributeSet?, int, int);
+    method public void addValueModifier(androidx.constraintlayout.widget.ConstraintLayout.ValueModifier!);
+    method protected void applyConstraintsFromLayoutParams(boolean, android.view.View!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method protected boolean dynamicUpdateConstraints(int, int);
+    method public void fillMetrics(androidx.constraintlayout.core.Metrics!);
+    method protected androidx.constraintlayout.widget.ConstraintLayout.LayoutParams! generateDefaultLayoutParams();
+    method public androidx.constraintlayout.widget.ConstraintLayout.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+    method public Object! getDesignInformation(int, Object!);
+    method public int getMaxHeight();
+    method public int getMaxWidth();
+    method public int getMinHeight();
+    method public int getMinWidth();
+    method public int getOptimizationLevel();
+    method public String! getSceneString();
+    method public static androidx.constraintlayout.widget.SharedValues! getSharedValues();
+    method public android.view.View! getViewById(int);
+    method public final androidx.constraintlayout.core.widgets.ConstraintWidget! getViewWidget(android.view.View!);
+    method protected boolean isRtl();
+    method public void loadLayoutDescription(int);
+    method protected void parseLayoutDescription(int);
+    method protected void resolveMeasuredDimension(int, int, int, int, boolean, boolean);
+    method protected void resolveSystem(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int);
+    method public void setConstraintSet(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void setDesignInformation(int, Object!, Object!);
+    method public void setMaxHeight(int);
+    method public void setMaxWidth(int);
+    method public void setMinHeight(int);
+    method public void setMinWidth(int);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public void setOptimizationLevel(int);
+    method protected void setSelfDimensionBehaviour(androidx.constraintlayout.core.widgets.ConstraintWidgetContainer!, int, int, int, int);
+    method public void setState(int, int, int);
+    field public static final int DESIGN_INFO_ID = 0; // 0x0
+    field public static final String VERSION = "ConstraintLayout-2.2.0-alpha04";
+    field protected androidx.constraintlayout.widget.ConstraintLayoutStates! mConstraintLayoutSpec;
+    field protected boolean mDirtyHierarchy;
+    field protected androidx.constraintlayout.core.widgets.ConstraintWidgetContainer! mLayoutWidget;
+  }
+
+  public static class ConstraintLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public ConstraintLayout.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public ConstraintLayout.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public ConstraintLayout.LayoutParams(int, int);
+    method public String! getConstraintTag();
+    method public androidx.constraintlayout.core.widgets.ConstraintWidget! getConstraintWidget();
+    method public void reset();
+    method public void setWidgetDebugName(String!);
+    method public void validate();
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int CIRCLE = 8; // 0x8
+    field public static final int END = 7; // 0x7
+    field public static final int GONE_UNSET = -2147483648; // 0x80000000
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_HORIZONTAL_ONLY = 1; // 0x1
+    field public static final int WRAP_BEHAVIOR_INCLUDED = 0; // 0x0
+    field public static final int WRAP_BEHAVIOR_SKIPPED = 3; // 0x3
+    field public static final int WRAP_BEHAVIOR_VERTICAL_ONLY = 2; // 0x2
+    field public int baselineMargin;
+    field public int baselineToBaseline;
+    field public int baselineToBottom;
+    field public int baselineToTop;
+    field public int bottomToBottom;
+    field public int bottomToTop;
+    field public float circleAngle;
+    field public int circleConstraint;
+    field public int circleRadius;
+    field public boolean constrainedHeight;
+    field public boolean constrainedWidth;
+    field public String! constraintTag;
+    field public String! dimensionRatio;
+    field public int editorAbsoluteX;
+    field public int editorAbsoluteY;
+    field public int endToEnd;
+    field public int endToStart;
+    field public int goneBaselineMargin;
+    field public int goneBottomMargin;
+    field public int goneEndMargin;
+    field public int goneLeftMargin;
+    field public int goneRightMargin;
+    field public int goneStartMargin;
+    field public int goneTopMargin;
+    field public int guideBegin;
+    field public int guideEnd;
+    field public float guidePercent;
+    field public boolean guidelineUseRtl;
+    field public boolean helped;
+    field public float horizontalBias;
+    field public int horizontalChainStyle;
+    field public float horizontalWeight;
+    field public int leftToLeft;
+    field public int leftToRight;
+    field public int matchConstraintDefaultHeight;
+    field public int matchConstraintDefaultWidth;
+    field public int matchConstraintMaxHeight;
+    field public int matchConstraintMaxWidth;
+    field public int matchConstraintMinHeight;
+    field public int matchConstraintMinWidth;
+    field public float matchConstraintPercentHeight;
+    field public float matchConstraintPercentWidth;
+    field public int orientation;
+    field public int rightToLeft;
+    field public int rightToRight;
+    field public int startToEnd;
+    field public int startToStart;
+    field public int topToBottom;
+    field public int topToTop;
+    field public float verticalBias;
+    field public int verticalChainStyle;
+    field public float verticalWeight;
+    field public int wrapBehaviorInParent;
+  }
+
+  public static interface ConstraintLayout.ValueModifier {
+    method public boolean update(int, int, int, android.view.View!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+  }
+
+  public class ConstraintLayoutStates {
+    method public boolean needsToChange(int, float, float);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public void updateConstraints(int, float, float);
+    field public static final String TAG = "ConstraintLayoutStates";
+  }
+
+  public class ConstraintLayoutStatistics {
+    ctor public ConstraintLayoutStatistics(androidx.constraintlayout.widget.ConstraintLayout!);
+    ctor public ConstraintLayoutStatistics(androidx.constraintlayout.widget.ConstraintLayoutStatistics!);
+    method public void attach(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public androidx.constraintlayout.widget.ConstraintLayoutStatistics! clone();
+    method public void detach();
+    method public long getValue(int);
+    method public void logSummary(String!);
+    method public void logSummary(String!, androidx.constraintlayout.widget.ConstraintLayoutStatistics!);
+    method public void reset();
+    field public static final int DURATION_OF_CHILD_MEASURES = 5; // 0x5
+    field public static final int DURATION_OF_LAYOUT = 7; // 0x7
+    field public static final int DURATION_OF_MEASURES = 6; // 0x6
+    field public static final int NUMBER_OF_CHILD_MEASURES = 4; // 0x4
+    field public static final int NUMBER_OF_CHILD_VIEWS = 3; // 0x3
+    field public static final int NUMBER_OF_EQUATIONS = 9; // 0x9
+    field public static final int NUMBER_OF_LAYOUTS = 1; // 0x1
+    field public static final int NUMBER_OF_ON_MEASURES = 2; // 0x2
+    field public static final int NUMBER_OF_SIMPLE_EQUATIONS = 10; // 0xa
+    field public static final int NUMBER_OF_VARIABLES = 8; // 0x8
+  }
+
+  public class ConstraintProperties {
+    ctor public ConstraintProperties(android.view.View!);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToHorizontalChain(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToHorizontalChainRTL(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! addToVerticalChain(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! alpha(float);
+    method public void apply();
+    method public androidx.constraintlayout.widget.ConstraintProperties! center(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontally(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontally(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontallyRtl(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerHorizontallyRtl(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerVertically(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! centerVertically(int, int, int, int, int, int, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! connect(int, int, int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainDefaultHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainDefaultWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMaxHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMaxWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMinHeight(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainMinWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! constrainWidth(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! dimensionRatio(String!);
+    method public androidx.constraintlayout.widget.ConstraintProperties! elevation(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! goneMargin(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalBias(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalChainStyle(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! horizontalWeight(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! margin(int, int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeConstraints(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeFromHorizontalChain();
+    method public androidx.constraintlayout.widget.ConstraintProperties! removeFromVerticalChain();
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotation(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotationX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! rotationY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! scaleX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! scaleY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivot(float, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivotX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! transformPivotY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translation(float, float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationX(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationY(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! translationZ(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalBias(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalChainStyle(int);
+    method public androidx.constraintlayout.widget.ConstraintProperties! verticalWeight(float);
+    method public androidx.constraintlayout.widget.ConstraintProperties! visibility(int);
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int END = 7; // 0x7
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+  }
+
+  public class ConstraintSet {
+    ctor public ConstraintSet();
+    method public void addColorAttributes(java.lang.String!...!);
+    method public void addFloatAttributes(java.lang.String!...!);
+    method public void addIntAttributes(java.lang.String!...!);
+    method public void addStringAttributes(java.lang.String!...!);
+    method public void addToHorizontalChain(int, int, int);
+    method public void addToHorizontalChainRTL(int, int, int);
+    method public void addToVerticalChain(int, int, int);
+    method public void applyCustomAttributes(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void applyDeltaFrom(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void applyTo(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void applyToHelper(androidx.constraintlayout.widget.ConstraintHelper!, androidx.constraintlayout.core.widgets.ConstraintWidget!, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!, android.util.SparseArray!);
+    method public void applyToLayoutParams(int, androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+    method public void applyToWithoutCustom(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public static androidx.constraintlayout.widget.ConstraintSet.Constraint! buildDelta(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public void center(int, int, int, int, int, int, int, float);
+    method public void centerHorizontally(int, int);
+    method public void centerHorizontally(int, int, int, int, int, int, int, float);
+    method public void centerHorizontallyRtl(int, int);
+    method public void centerHorizontallyRtl(int, int, int, int, int, int, int, float);
+    method public void centerVertically(int, int);
+    method public void centerVertically(int, int, int, int, int, int, int, float);
+    method public void clear(int);
+    method public void clear(int, int);
+    method public void clone(android.content.Context!, int);
+    method public void clone(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void clone(androidx.constraintlayout.widget.Constraints!);
+    method public void clone(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void connect(int, int, int, int);
+    method public void connect(int, int, int, int, int);
+    method public void constrainCircle(int, int, int, float);
+    method public void constrainDefaultHeight(int, int);
+    method public void constrainDefaultWidth(int, int);
+    method public void constrainHeight(int, int);
+    method public void constrainMaxHeight(int, int);
+    method public void constrainMaxWidth(int, int);
+    method public void constrainMinHeight(int, int);
+    method public void constrainMinWidth(int, int);
+    method public void constrainPercentHeight(int, float);
+    method public void constrainPercentWidth(int, float);
+    method public void constrainWidth(int, int);
+    method public void constrainedHeight(int, boolean);
+    method public void constrainedWidth(int, boolean);
+    method public void create(int, int);
+    method public void createBarrier(int, int, int, int...!);
+    method public void createHorizontalChain(int, int, int, int, int[]!, float[]!, int);
+    method public void createHorizontalChainRtl(int, int, int, int, int[]!, float[]!, int);
+    method public void createVerticalChain(int, int, int, int, int[]!, float[]!, int);
+    method public void dump(androidx.constraintlayout.motion.widget.MotionScene!, int...!);
+    method public boolean getApplyElevation(int);
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! getConstraint(int);
+    method public java.util.HashMap! getCustomAttributeSet();
+    method public int getHeight(int);
+    method public int[]! getKnownIds();
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! getParameters(int);
+    method public int[]! getReferencedIds(int);
+    method public String![]! getStateLabels();
+    method public int getVisibility(int);
+    method public int getVisibilityMode(int);
+    method public int getWidth(int);
+    method public boolean isForceId();
+    method public boolean isValidateOnParse();
+    method public void load(android.content.Context!, int);
+    method public void load(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public boolean matchesLabels(java.lang.String!...!);
+    method public void parseColorAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseFloatAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseIntAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void parseStringAttributes(androidx.constraintlayout.widget.ConstraintSet.Constraint!, String!);
+    method public void readFallback(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void readFallback(androidx.constraintlayout.widget.ConstraintSet!);
+    method public void removeAttribute(String!);
+    method public void removeFromHorizontalChain(int);
+    method public void removeFromVerticalChain(int);
+    method public void setAlpha(int, float);
+    method public void setApplyElevation(int, boolean);
+    method public void setBarrierType(int, int);
+    method public void setColorValue(int, String!, int);
+    method public void setDimensionRatio(int, String!);
+    method public void setEditorAbsoluteX(int, int);
+    method public void setEditorAbsoluteY(int, int);
+    method public void setElevation(int, float);
+    method public void setFloatValue(int, String!, float);
+    method public void setForceId(boolean);
+    method public void setGoneMargin(int, int, int);
+    method public void setGuidelineBegin(int, int);
+    method public void setGuidelineEnd(int, int);
+    method public void setGuidelinePercent(int, float);
+    method public void setHorizontalBias(int, float);
+    method public void setHorizontalChainStyle(int, int);
+    method public void setHorizontalWeight(int, float);
+    method public void setIntValue(int, String!, int);
+    method public void setLayoutWrapBehavior(int, int);
+    method public void setMargin(int, int, int);
+    method public void setReferencedIds(int, int...!);
+    method public void setRotation(int, float);
+    method public void setRotationX(int, float);
+    method public void setRotationY(int, float);
+    method public void setScaleX(int, float);
+    method public void setScaleY(int, float);
+    method public void setStateLabels(String!);
+    method public void setStateLabelsList(java.lang.String!...!);
+    method public void setStringValue(int, String!, String!);
+    method public void setTransformPivot(int, float, float);
+    method public void setTransformPivotX(int, float);
+    method public void setTransformPivotY(int, float);
+    method public void setTranslation(int, float, float);
+    method public void setTranslationX(int, float);
+    method public void setTranslationY(int, float);
+    method public void setTranslationZ(int, float);
+    method public void setValidateOnParse(boolean);
+    method public void setVerticalBias(int, float);
+    method public void setVerticalChainStyle(int, int);
+    method public void setVerticalWeight(int, float);
+    method public void setVisibility(int, int);
+    method public void setVisibilityMode(int, int);
+    method public void writeState(java.io.Writer!, androidx.constraintlayout.widget.ConstraintLayout!, int) throws java.io.IOException;
+    field public static final int BASELINE = 5; // 0x5
+    field public static final int BOTTOM = 4; // 0x4
+    field public static final int CHAIN_PACKED = 2; // 0x2
+    field public static final int CHAIN_SPREAD = 0; // 0x0
+    field public static final int CHAIN_SPREAD_INSIDE = 1; // 0x1
+    field public static final int CIRCLE_REFERENCE = 8; // 0x8
+    field public static final int END = 7; // 0x7
+    field public static final int GONE = 8; // 0x8
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int HORIZONTAL_GUIDELINE = 0; // 0x0
+    field public static final int INVISIBLE = 4; // 0x4
+    field public static final int LEFT = 1; // 0x1
+    field public static final int MATCH_CONSTRAINT = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_PERCENT = 2; // 0x2
+    field public static final int MATCH_CONSTRAINT_SPREAD = 0; // 0x0
+    field public static final int MATCH_CONSTRAINT_WRAP = 1; // 0x1
+    field public static final int PARENT_ID = 0; // 0x0
+    field public static final int RIGHT = 2; // 0x2
+    field public static final int ROTATE_LEFT_OF_PORTRATE = 4; // 0x4
+    field public static final int ROTATE_NONE = 0; // 0x0
+    field public static final int ROTATE_PORTRATE_OF_LEFT = 2; // 0x2
+    field public static final int ROTATE_PORTRATE_OF_RIGHT = 1; // 0x1
+    field public static final int ROTATE_RIGHT_OF_PORTRATE = 3; // 0x3
+    field public static final int START = 6; // 0x6
+    field public static final int TOP = 3; // 0x3
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int VERTICAL = 1; // 0x1
+    field public static final int VERTICAL_GUIDELINE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_IGNORE = 1; // 0x1
+    field public static final int VISIBILITY_MODE_NORMAL = 0; // 0x0
+    field public static final int VISIBLE = 0; // 0x0
+    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
+    field public String! derivedState;
+    field public String! mIdString;
+    field public int mRotate;
+  }
+
+  public static class ConstraintSet.Constraint {
+    ctor public ConstraintSet.Constraint();
+    method public void applyDelta(androidx.constraintlayout.widget.ConstraintSet.Constraint!);
+    method public void applyTo(androidx.constraintlayout.widget.ConstraintLayout.LayoutParams!);
+    method public androidx.constraintlayout.widget.ConstraintSet.Constraint! clone();
+    method public void printDelta(String!);
+    field public final androidx.constraintlayout.widget.ConstraintSet.Layout! layout;
+    field public java.util.HashMap! mCustomConstraints;
+    field public final androidx.constraintlayout.widget.ConstraintSet.Motion! motion;
+    field public final androidx.constraintlayout.widget.ConstraintSet.PropertySet! propertySet;
+    field public final androidx.constraintlayout.widget.ConstraintSet.Transform! transform;
+  }
+
+  public static class ConstraintSet.Layout {
+    ctor public ConstraintSet.Layout();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Layout!);
+    method public void dump(androidx.constraintlayout.motion.widget.MotionScene!, StringBuilder!);
+    field public static final int UNSET = -1; // 0xffffffff
+    field public static final int UNSET_GONE_MARGIN = -2147483648; // 0x80000000
+    field public int baselineMargin;
+    field public int baselineToBaseline;
+    field public int baselineToBottom;
+    field public int baselineToTop;
+    field public int bottomMargin;
+    field public int bottomToBottom;
+    field public int bottomToTop;
+    field public float circleAngle;
+    field public int circleConstraint;
+    field public int circleRadius;
+    field public boolean constrainedHeight;
+    field public boolean constrainedWidth;
+    field public String! dimensionRatio;
+    field public int editorAbsoluteX;
+    field public int editorAbsoluteY;
+    field public int endMargin;
+    field public int endToEnd;
+    field public int endToStart;
+    field public int goneBaselineMargin;
+    field public int goneBottomMargin;
+    field public int goneEndMargin;
+    field public int goneLeftMargin;
+    field public int goneRightMargin;
+    field public int goneStartMargin;
+    field public int goneTopMargin;
+    field public int guideBegin;
+    field public int guideEnd;
+    field public float guidePercent;
+    field public boolean guidelineUseRtl;
+    field public int heightDefault;
+    field public int heightMax;
+    field public int heightMin;
+    field public float heightPercent;
+    field public float horizontalBias;
+    field public int horizontalChainStyle;
+    field public float horizontalWeight;
+    field public int leftMargin;
+    field public int leftToLeft;
+    field public int leftToRight;
+    field public boolean mApply;
+    field public boolean mBarrierAllowsGoneWidgets;
+    field public int mBarrierDirection;
+    field public int mBarrierMargin;
+    field public String! mConstraintTag;
+    field public int mHeight;
+    field public int mHelperType;
+    field public boolean mIsGuideline;
+    field public boolean mOverride;
+    field public String! mReferenceIdString;
+    field public int[]! mReferenceIds;
+    field public int mWidth;
+    field public int mWrapBehavior;
+    field public int orientation;
+    field public int rightMargin;
+    field public int rightToLeft;
+    field public int rightToRight;
+    field public int startMargin;
+    field public int startToEnd;
+    field public int startToStart;
+    field public int topMargin;
+    field public int topToBottom;
+    field public int topToTop;
+    field public float verticalBias;
+    field public int verticalChainStyle;
+    field public float verticalWeight;
+    field public int widthDefault;
+    field public int widthMax;
+    field public int widthMin;
+    field public float widthPercent;
+  }
+
+  public static class ConstraintSet.Motion {
+    ctor public ConstraintSet.Motion();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Motion!);
+    field public int mAnimateCircleAngleTo;
+    field public int mAnimateRelativeTo;
+    field public boolean mApply;
+    field public int mDrawPath;
+    field public float mMotionStagger;
+    field public int mPathMotionArc;
+    field public float mPathRotate;
+    field public int mPolarRelativeTo;
+    field public int mQuantizeInterpolatorID;
+    field public String! mQuantizeInterpolatorString;
+    field public int mQuantizeInterpolatorType;
+    field public float mQuantizeMotionPhase;
+    field public int mQuantizeMotionSteps;
+    field public String! mTransitionEasing;
+  }
+
+  public static class ConstraintSet.PropertySet {
+    ctor public ConstraintSet.PropertySet();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.PropertySet!);
+    field public float alpha;
+    field public boolean mApply;
+    field public float mProgress;
+    field public int mVisibilityMode;
+    field public int visibility;
+  }
+
+  public static class ConstraintSet.Transform {
+    ctor public ConstraintSet.Transform();
+    method public void copyFrom(androidx.constraintlayout.widget.ConstraintSet.Transform!);
+    field public boolean applyElevation;
+    field public float elevation;
+    field public boolean mApply;
+    field public float rotation;
+    field public float rotationX;
+    field public float rotationY;
+    field public float scaleX;
+    field public float scaleY;
+    field public int transformPivotTarget;
+    field public float transformPivotX;
+    field public float transformPivotY;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+  }
+
+  public class Constraints extends android.view.ViewGroup {
+    ctor public Constraints(android.content.Context!);
+    ctor public Constraints(android.content.Context!, android.util.AttributeSet!);
+    ctor public Constraints(android.content.Context!, android.util.AttributeSet!, int);
+    method protected androidx.constraintlayout.widget.Constraints.LayoutParams! generateDefaultLayoutParams();
+    method public androidx.constraintlayout.widget.Constraints.LayoutParams! generateLayoutParams(android.util.AttributeSet!);
+    method public androidx.constraintlayout.widget.ConstraintSet! getConstraintSet();
+    field public static final String TAG = "Constraints";
+  }
+
+  public static class Constraints.LayoutParams extends androidx.constraintlayout.widget.ConstraintLayout.LayoutParams {
+    ctor public Constraints.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public Constraints.LayoutParams(androidx.constraintlayout.widget.Constraints.LayoutParams!);
+    ctor public Constraints.LayoutParams(int, int);
+    field public float alpha;
+    field public boolean applyElevation;
+    field public float elevation;
+    field public float rotation;
+    field public float rotationX;
+    field public float rotationY;
+    field public float scaleX;
+    field public float scaleY;
+    field public float transformPivotX;
+    field public float transformPivotY;
+    field public float translationX;
+    field public float translationY;
+    field public float translationZ;
+  }
+
+  public abstract class ConstraintsChangedListener {
+    ctor public ConstraintsChangedListener();
+    method public void postLayoutChange(int, int);
+    method public void preLayoutChange(int, int);
+  }
+
+  public class Group extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public Group(android.content.Context!);
+    ctor public Group(android.content.Context!, android.util.AttributeSet!);
+    ctor public Group(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onAttachedToWindow();
+  }
+
+  public class Guideline extends android.view.View {
+    ctor public Guideline(android.content.Context!);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public Guideline(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public void setFilterRedundantCalls(boolean);
+    method public void setGuidelineBegin(int);
+    method public void setGuidelineEnd(int);
+    method public void setGuidelinePercent(float);
+  }
+
+  public class Placeholder extends android.view.View {
+    ctor public Placeholder(android.content.Context!);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public Placeholder(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public android.view.View! getContent();
+    method public int getEmptyVisibility();
+    method public void onDraw(android.graphics.Canvas);
+    method public void setContentId(int);
+    method public void setEmptyVisibility(int);
+    method public void updatePostMeasure(androidx.constraintlayout.widget.ConstraintLayout!);
+    method public void updatePreLayout(androidx.constraintlayout.widget.ConstraintLayout!);
+  }
+
+  public class ReactiveGuide extends android.view.View implements androidx.constraintlayout.widget.SharedValues.SharedValuesListener {
+    ctor public ReactiveGuide(android.content.Context!);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public ReactiveGuide(android.content.Context!, android.util.AttributeSet!, int, int);
+    method public int getApplyToConstraintSetId();
+    method public int getAttributeId();
+    method public boolean isAnimatingChange();
+    method public void onNewValue(int, int, int);
+    method public void setAnimateChange(boolean);
+    method public void setApplyToConstraintSetId(int);
+    method public void setAttributeId(int);
+    method public void setGuidelineBegin(int);
+    method public void setGuidelineEnd(int);
+    method public void setGuidelinePercent(float);
+  }
+
+  public class SharedValues {
+    ctor public SharedValues();
+    method public void addListener(int, androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    method public void clearListeners();
+    method public void fireNewValue(int, int);
+    method public int getValue(int);
+    method public void removeListener(androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    method public void removeListener(int, androidx.constraintlayout.widget.SharedValues.SharedValuesListener!);
+    field public static final int UNSET = -1; // 0xffffffff
+  }
+
+  public static interface SharedValues.SharedValuesListener {
+    method public void onNewValue(int, int, int);
+  }
+
+  public class StateSet {
+    ctor public StateSet(android.content.Context!, org.xmlpull.v1.XmlPullParser!);
+    method public int convertToConstraintSet(int, int, float, float);
+    method public boolean needsToChange(int, float, float);
+    method public void setOnConstraintsChanged(androidx.constraintlayout.widget.ConstraintsChangedListener!);
+    method public int stateGetConstraintID(int, int, int);
+    method public int updateConstraints(int, int, float, float);
+    field public static final String TAG = "ConstraintLayoutStates";
+  }
+
+  public abstract class VirtualLayout extends androidx.constraintlayout.widget.ConstraintHelper {
+    ctor public VirtualLayout(android.content.Context!);
+    ctor public VirtualLayout(android.content.Context!, android.util.AttributeSet!);
+    ctor public VirtualLayout(android.content.Context!, android.util.AttributeSet!, int);
+    method public void onAttachedToWindow();
+    method public void onMeasure(androidx.constraintlayout.core.widgets.VirtualLayout!, int, int);
+  }
+
+}
+
diff --git a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenParametrizedTest.kt b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenParametrizedTest.kt
index ec8d536..74c7f09 100644
--- a/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenParametrizedTest.kt
+++ b/core/core-splashscreen/src/androidTest/java/androidx/core/splashscreen/test/SplashscreenParametrizedTest.kt
@@ -19,6 +19,8 @@
 import android.content.Intent
 import android.graphics.Bitmap
 import android.os.Bundle
+import android.util.Base64
+import android.util.Log
 import android.view.View
 import android.view.ViewTreeObserver
 import androidx.core.splashscreen.SplashScreenViewProvider
@@ -28,6 +30,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.screenshot.matchers.MSSIMMatcher
 import androidx.test.uiautomator.UiDevice
+import java.io.ByteArrayOutputStream
 import java.io.File
 import java.io.FileOutputStream
 import java.io.IOException
@@ -63,6 +66,8 @@
                 arrayOf("AppCompat", SplashScreenAppCompatTestActivity::class)
             )
         }
+
+        const val TAG = "SplashscreenParameterizedTest"
     }
 
     @Before
@@ -310,6 +315,12 @@
                 )
 
         if (!matcher.matches) {
+            // Serialize the screenshots and output them through Logcat so as to gather more details
+            // for debugging.
+            logLongMessage(Log::e, TAG, "before", beforeScreenshot.toBase64String())
+            logLongMessage(Log::e, TAG, "after", afterScreenshot.toBase64String())
+            matcher.diff?.let { logLongMessage(Log::e, TAG, "diff", it.toBase64String()) }
+
             val bundle = Bundle()
             val diff = matcher.diff?.writeToDevice("diff.png")
             bundle.putString("splashscreen_diff", diff?.absolutePath)
@@ -330,6 +341,50 @@
         }
     }
 
+    /**
+     * A log message has a maximum of 4096 bytes, where date / time, tag, process, etc. included.
+     *
+     * Therefore, we should chunk a large message into some smaller ones.
+     */
+    private fun logLongMessage(
+        logger: (tag: String, msg: String) -> Int,
+        tag: String,
+        title: String,
+        msg: String
+    ) {
+        val chunks = msg.chunked(4000)
+        logger(tag, "$title ${chunks.size}")
+
+        for ((i, chunk) in chunks.withIndex()) {
+            logger(tag, title + " $i/${chunks.size} " + chunk)
+        }
+    }
+
+    /**
+     * Serialize a bitmap into a string in Base64 encoding so that we could output it through logs
+     * when comparisons fail.
+     */
+    private fun Bitmap.toBase64String(): String {
+        val scaledBitmap =
+            Bitmap.createScaledBitmap(
+                this,
+                // Reduce the size of the bitmap
+                width * 3 shr 2,
+                height * 3 shr 2,
+                false
+            )
+        val outputStream = ByteArrayOutputStream()
+        scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
+
+        val bytes = outputStream.toByteArray()
+        val str =
+            Base64.encodeToString(
+                bytes,
+                Base64.NO_WRAP // Not to wrap here as we are going to wrap on our own later
+            )
+        return str
+    }
+
     private fun Bitmap.writeToDevice(name: String): File {
         return writeToDevice(
             { compress(Bitmap.CompressFormat.PNG, 0 /*ignored for png*/, it) },
diff --git a/core/core-telecom/src/main/res/values-bg/strings.xml b/core/core-telecom/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..91d381b
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-bg/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "Слушалка"
+    "Слушалки с кабел"
+    "Високоговорител"
+
diff --git a/core/core-telecom/src/main/res/values-en-rCA/strings.xml b/core/core-telecom/src/main/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..ae0ae39
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-en-rCA/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "Earpiece"
+    "Wired headset"
+    "Speaker"
+
diff --git a/core/core-telecom/src/main/res/values-en-rXC/strings.xml b/core/core-telecom/src/main/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..db0d654
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-en-rXC/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎Earpiece‎‏‎‎‏‎"
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎Wired headset‎‏‎‎‏‎"
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎Speaker‎‏‎‎‏‎"
+
diff --git a/core/core-telecom/src/main/res/values-fi/strings.xml b/core/core-telecom/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..1772c83
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-fi/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "Kaiutin"
+    "Langallinen kuulokemikrofoni"
+    "Kaiutin"
+
diff --git a/core/core-telecom/src/main/res/values-hi/strings.xml b/core/core-telecom/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..3a847ac
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-hi/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "ईयरपीस"
+    "वायर वाला हेडसेट"
+    "स्पीकर"
+
diff --git a/core/core-telecom/src/main/res/values-it/strings.xml b/core/core-telecom/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..1ffa5ad
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-it/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "Auricolare"
+    "Cuffie con cavo"
+    "Speaker"
+
diff --git a/core/core-telecom/src/main/res/values-ja/strings.xml b/core/core-telecom/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..fecacc1
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-ja/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "受話口"
+    "有線ヘッドセット"
+    "スピーカー"
+
diff --git a/core/core-telecom/src/main/res/values-ka/strings.xml b/core/core-telecom/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..d93c507
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-ka/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "ყურმილი"
+    "სადენიანი ყურსაცვამი"
+    "დინამიკი"
+
diff --git a/core/core-telecom/src/main/res/values-lo/strings.xml b/core/core-telecom/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..fae8f3f
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-lo/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "ຫູຟັງ"
+    "ຊຸດຫູຟັງແບບມີສາຍ"
+    "ລຳໂພງ"
+
diff --git a/core/core-telecom/src/main/res/values-ml/strings.xml b/core/core-telecom/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..7efb254
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-ml/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "ഇയർഫോൺ"
+    "വയേർഡ് ഹെഡ്‌സെറ്റ്"
+    "സ്പീക്കർ"
+
diff --git a/core/core-telecom/src/main/res/values-ne/strings.xml b/core/core-telecom/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..30d613e
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-ne/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "इयरपिस"
+    "तारसहितको हेडसेट"
+    "स्पिकर"
+
diff --git a/core/core-telecom/src/main/res/values-pt-rPT/strings.xml b/core/core-telecom/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..ee657a4
--- /dev/null
+++ b/core/core-telecom/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    "Auricular"
+    "Auscultadores com microfone integrado com fios"
+    "Altifalante"
+
diff --git a/credentials/credentials-play-services-auth/build.gradle b/credentials/credentials-play-services-auth/build.gradle
index abd64a6..30d02c4 100644
--- a/credentials/credentials-play-services-auth/build.gradle
+++ b/credentials/credentials-play-services-auth/build.gradle
@@ -53,6 +53,11 @@
         exclude group: "androidx.core"
     }
 
+    implementation(libs.playServicesIdentityCredentials){
+        exclude group: "androidx.loader"
+        exclude group: "androidx.core"
+    }
+
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.testExtJunit)
     androidTestImplementation(libs.testCore)
diff --git a/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/getdigitalcredential/CredentialProviderGetDigitalCredentialControllerTest.kt b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/getdigitalcredential/CredentialProviderGetDigitalCredentialControllerTest.kt
new file mode 100644
index 0000000..f936675
--- /dev/null
+++ b/credentials/credentials-play-services-auth/src/androidTest/java/androidx/credentials/playservices/getdigitalcredential/CredentialProviderGetDigitalCredentialControllerTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2024 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.credentials.playservices.getdigitalcredential
+
+import android.content.ComponentName
+import androidx.credentials.GetCredentialRequest
+import androidx.credentials.GetDigitalCredentialOption
+import androidx.credentials.playservices.TestCredentialsActivity
+import androidx.credentials.playservices.TestUtils
+import androidx.credentials.playservices.controllers.GetRestoreCredential.CredentialProviderGetDigitalCredentialController
+import androidx.test.core.app.ActivityScenario
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class CredentialProviderGetDigitalCredentialControllerTest {
+    @Test
+    fun convertRequestToPlayServices_success() {
+        val request =
+            GetCredentialRequest(
+                credentialOptions =
+                    listOf(
+                        GetDigitalCredentialOption("{\"request\":{\"json\":{\"test\":\"val\"}}}"),
+                        GetDigitalCredentialOption("{\"request\":\"val\",\"key2\":\"val2\"}"),
+                    ),
+                origin = "origin",
+                preferIdentityDocUi = true,
+                preferUiBrandingComponentName = ComponentName("pkg", "cls"),
+                preferImmediatelyAvailableCredentials = true,
+            )
+        val activityScenario = ActivityScenario.launch(TestCredentialsActivity::class.java)
+
+        activityScenario.onActivity { activity: TestCredentialsActivity? ->
+            val convertedRequest =
+                CredentialProviderGetDigitalCredentialController(activity!!)
+                    .convertRequestToPlayServices(request)
+
+            assertThat(convertedRequest.origin).isEqualTo(request.origin)
+            TestUtils.equals(
+                convertedRequest.data,
+                GetCredentialRequest.getRequestMetadataBundle(request)
+            )
+            request.credentialOptions.forEachIndexed { idx, expectedOption ->
+                val actualOption = convertedRequest.credentialOptions[idx]
+                assertThat(actualOption.type).isEqualTo(expectedOption.type)
+                if (expectedOption is GetDigitalCredentialOption) {
+                    assertThat(actualOption.requestMatcher).isEqualTo(expectedOption.requestJson)
+                }
+                TestUtils.equals(actualOption.credentialRetrievalData, expectedOption.requestData)
+                TestUtils.equals(actualOption.candidateQueryData, expectedOption.candidateQueryData)
+            }
+        }
+    }
+}
diff --git a/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml b/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
index 24737ae..5a9ac0b 100644
--- a/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
+++ b/credentials/credentials-play-services-auth/src/main/AndroidManifest.xml
@@ -33,5 +33,13 @@
             android:fitsSystemWindows="true"
             android:theme="@style/Theme.Hidden">
         
+        
+            android:name="androidx.credentials.playservices.IdentityCredentialApiHiddenActivity"
+            android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
+            android:exported="false"
+            android:enabled="true"
+            android:fitsSystemWindows="true"
+            android:theme="@style/Theme.Hidden">
+        
     
 
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
index 8bed458..c02960a 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/CredentialProviderPlayServicesImpl.kt
@@ -32,6 +32,7 @@
 import androidx.credentials.CredentialProvider
 import androidx.credentials.GetCredentialRequest
 import androidx.credentials.GetCredentialResponse
+import androidx.credentials.GetDigitalCredentialOption
 import androidx.credentials.GetRestoreCredentialOption
 import androidx.credentials.exceptions.ClearCredentialException
 import androidx.credentials.exceptions.ClearCredentialProviderConfigurationException
@@ -44,6 +45,7 @@
 import androidx.credentials.playservices.controllers.CreatePassword.CredentialProviderCreatePasswordController
 import androidx.credentials.playservices.controllers.CreatePublicKeyCredential.CredentialProviderCreatePublicKeyCredentialController
 import androidx.credentials.playservices.controllers.CreateRestoreCredential.CredentialProviderCreateRestoreCredentialController
+import androidx.credentials.playservices.controllers.GetRestoreCredential.CredentialProviderGetDigitalCredentialController
 import androidx.credentials.playservices.controllers.GetRestoreCredential.CredentialProviderGetRestoreCredentialController
 import androidx.credentials.playservices.controllers.GetSignInIntent.CredentialProviderGetSignInIntentController
 import com.google.android.gms.auth.api.identity.Identity
@@ -72,7 +74,23 @@
         if (cancellationReviewer(cancellationSignal)) {
             return
         }
-        if (isGetRestoreCredentialRequest(request)) {
+        if (isDigitalCredentialRequest(request)) {
+            if (!isAvailableOnDevice(MIN_GMS_APK_VERSION_DIGITAL_CRED)) {
+                cancellationReviewerWithCallback(cancellationSignal) {
+                    executor.execute {
+                        callback.onError(
+                            GetCredentialProviderConfigurationException(
+                                "this device requires a Google Play Services update for the" +
+                                    " given feature to be supported"
+                            )
+                        )
+                    }
+                }
+                return
+            }
+            CredentialProviderGetDigitalCredentialController(context)
+                .invokePlayServices(request, callback, executor, cancellationSignal)
+        } else if (isGetRestoreCredentialRequest(request)) {
             if (!isAvailableOnDevice(MIN_GMS_APK_VERSION_RESTORE_CRED)) {
                 cancellationReviewerWithCallback(cancellationSignal) {
                     executor.execute {
@@ -263,6 +281,8 @@
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) const val MIN_GMS_APK_VERSION = 230815045
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         const val MIN_GMS_APK_VERSION_RESTORE_CRED = 242200000
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        const val MIN_GMS_APK_VERSION_DIGITAL_CRED = 243100000
 
         internal fun cancellationReviewerWithCallback(
             cancellationSignal: CancellationSignal?,
@@ -302,5 +322,14 @@
             }
             return false
         }
+
+        internal fun isDigitalCredentialRequest(request: GetCredentialRequest): Boolean {
+            for (option in request.credentialOptions) {
+                if (option is GetDigitalCredentialOption) {
+                    return true
+                }
+            }
+            return false
+        }
     }
 }
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
index 03d22ff..93216a1 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/HiddenActivity.kt
@@ -32,6 +32,8 @@
 import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.GET_INTERRUPTED
 import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.GET_NO_CREDENTIALS
 import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.GET_UNKNOWN
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.reportError
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.reportResult
 import com.google.android.gms.auth.api.identity.BeginSignInRequest
 import com.google.android.gms.auth.api.identity.GetSignInIntentRequest
 import com.google.android.gms.auth.api.identity.Identity
@@ -150,11 +152,7 @@
     }
 
     private fun setupFailure(resultReceiver: ResultReceiver, errName: String, errMsg: String) {
-        val bundle = Bundle()
-        bundle.putBoolean(CredentialProviderBaseController.FAILURE_RESPONSE_TAG, true)
-        bundle.putString(CredentialProviderBaseController.EXCEPTION_TYPE_TAG, errName)
-        bundle.putString(CredentialProviderBaseController.EXCEPTION_MESSAGE_TAG, errMsg)
-        resultReceiver.send(Integer.MAX_VALUE, bundle)
+        resultReceiver.reportError(errName, errMsg)
         finish()
     }
 
@@ -336,11 +334,11 @@
 
     override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
         super.onActivityResult(requestCode, resultCode, data)
-        val bundle = Bundle()
-        bundle.putBoolean(CredentialProviderBaseController.FAILURE_RESPONSE_TAG, false)
-        bundle.putInt(CredentialProviderBaseController.ACTIVITY_REQUEST_CODE_TAG, requestCode)
-        bundle.putParcelable(CredentialProviderBaseController.RESULT_DATA_TAG, data)
-        resultReceiver?.send(resultCode, bundle)
+        resultReceiver?.reportResult(
+            requestCode = requestCode,
+            data = data,
+            resultCode = resultCode
+        )
         mWaitingForActivityResult = false
         finish()
     }
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/IdentityCredentialApiHiddenActivity.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/IdentityCredentialApiHiddenActivity.kt
new file mode 100644
index 0000000..7270a9a
--- /dev/null
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/IdentityCredentialApiHiddenActivity.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("Deprecation")
+
+package androidx.credentials.playservices
+
+import android.app.Activity
+import android.app.PendingIntent
+import android.content.Intent
+import android.os.Bundle
+import android.os.ResultReceiver
+import androidx.annotation.RestrictTo
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.GET_UNKNOWN
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.reportError
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController.Companion.reportResult
+
+/** An activity used to ensure all required API versions work as intended. */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@Suppress("ForbiddenSuperClass")
+open class IdentityCredentialApiHiddenActivity : Activity() {
+
+    private var resultReceiver: ResultReceiver? = null
+    private var mWaitingForActivityResult = false
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        overridePendingTransition(0, 0)
+        resultReceiver =
+            intent.getParcelableExtra(CredentialProviderBaseController.RESULT_RECEIVER_TAG)
+        if (resultReceiver == null) {
+            finish()
+        }
+
+        restoreState(savedInstanceState)
+        if (mWaitingForActivityResult) {
+            return
+            // Past call still active
+        }
+        val pendingIntent: PendingIntent? =
+            intent.getParcelableExtra(CredentialProviderBaseController.EXTRA_GET_CREDENTIAL_INTENT)
+
+        if (pendingIntent != null) {
+            startIntentSenderForResult(
+                pendingIntent.intentSender,
+                /* requestCode= */ CredentialProviderBaseController.CONTROLLER_REQUEST_CODE,
+                /* fillInIntent= */ null,
+                /* flagsMask= */ 0,
+                /* flagsValues= */ 0,
+                /* extraFlags= */ 0,
+                /* options = */ null
+            )
+        } else {
+            resultReceiver?.reportError(errName = GET_UNKNOWN, errMsg = "Internal error")
+            finish()
+        }
+    }
+
+    private fun restoreState(savedInstanceState: Bundle?) {
+        if (savedInstanceState != null) {
+            mWaitingForActivityResult = savedInstanceState.getBoolean(KEY_AWAITING_RESULT, false)
+        }
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult)
+        super.onSaveInstanceState(outState)
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        resultReceiver?.reportResult(
+            requestCode = requestCode,
+            resultCode = resultCode,
+            data = data
+        )
+        mWaitingForActivityResult = false
+        finish()
+    }
+
+    companion object {
+        private const val KEY_AWAITING_RESULT = "androidx.credentials.playservices.AWAITING_RESULT"
+    }
+}
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
index 584fc1be..b5719fb 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CredentialProviderBaseController.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.Intent
+import android.os.Bundle
 import android.os.Parcel
 import android.os.ResultReceiver
 import androidx.credentials.exceptions.CreateCredentialCancellationException
@@ -44,7 +45,7 @@
             )
 
         // Generic controller request code used by all controllers
-        @JvmStatic protected val CONTROLLER_REQUEST_CODE: Int = 1
+        @JvmStatic internal val CONTROLLER_REQUEST_CODE: Int = 1
 
         /** -- Used to avoid reflection, these constants map errors from HiddenActivity -- */
         const val GET_CANCELED = "GET_CANCELED_TAG"
@@ -79,6 +80,9 @@
         // Key for the result intent to send back to the controller
         const val RESULT_DATA_TAG = "RESULT_DATA"
 
+        // Key for the actual parcelable type sent to the hidden activity
+        const val EXTRA_GET_CREDENTIAL_INTENT = "EXTRA_GET_CREDENTIAL_INTENT"
+
         // Key for the failure boolean sent back from hidden activity to controller
         const val FAILURE_RESPONSE_TAG = "FAILURE_RESPONSE"
 
@@ -115,6 +119,22 @@
             }
         }
 
+        internal fun ResultReceiver.reportError(errName: String, errMsg: String) {
+            val bundle = Bundle()
+            bundle.putBoolean(FAILURE_RESPONSE_TAG, true)
+            bundle.putString(EXCEPTION_TYPE_TAG, errName)
+            bundle.putString(EXCEPTION_MESSAGE_TAG, errMsg)
+            this.send(Integer.MAX_VALUE, bundle)
+        }
+
+        internal fun ResultReceiver.reportResult(requestCode: Int, resultCode: Int, data: Intent?) {
+            val bundle = Bundle()
+            bundle.putBoolean(FAILURE_RESPONSE_TAG, false)
+            bundle.putInt(ACTIVITY_REQUEST_CODE_TAG, requestCode)
+            bundle.putParcelable(RESULT_DATA_TAG, data)
+            this.send(resultCode, bundle)
+        }
+
         internal fun createCredentialExceptionTypeToException(
             typeName: String?,
             msg: String?
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/GetDigitalCredential/CredentialProviderGetDigitalCredentialController.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/GetDigitalCredential/CredentialProviderGetDigitalCredentialController.kt
new file mode 100644
index 0000000..d2e82a8
--- /dev/null
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/GetDigitalCredential/CredentialProviderGetDigitalCredentialController.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2024 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.credentials.playservices.controllers.GetRestoreCredential
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.CancellationSignal
+import android.os.Handler
+import android.os.Looper
+import android.os.ResultReceiver
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.credentials.Credential
+import androidx.credentials.CredentialManagerCallback
+import androidx.credentials.DigitalCredential
+import androidx.credentials.GetCredentialRequest
+import androidx.credentials.GetCredentialResponse
+import androidx.credentials.GetDigitalCredentialOption
+import androidx.credentials.exceptions.GetCredentialCancellationException
+import androidx.credentials.exceptions.GetCredentialException
+import androidx.credentials.exceptions.GetCredentialInterruptedException
+import androidx.credentials.exceptions.GetCredentialUnknownException
+import androidx.credentials.internal.toJetpackGetException
+import androidx.credentials.playservices.CredentialProviderPlayServicesImpl
+import androidx.credentials.playservices.IdentityCredentialApiHiddenActivity
+import androidx.credentials.playservices.controllers.CredentialProviderBaseController
+import androidx.credentials.playservices.controllers.CredentialProviderController
+import com.google.android.gms.common.api.ApiException
+import com.google.android.gms.common.api.CommonStatusCodes
+import com.google.android.gms.identitycredentials.IdentityCredentialManager
+import com.google.android.gms.identitycredentials.IntentHelper
+import java.util.concurrent.Executor
+
+/** A controller to handle the GetRestoreCredential flow with play services. */
+internal class CredentialProviderGetDigitalCredentialController(private val context: Context) :
+    CredentialProviderController<
+        GetCredentialRequest,
+        com.google.android.gms.identitycredentials.GetCredentialRequest,
+        com.google.android.gms.identitycredentials.GetCredentialResponse,
+        GetCredentialResponse,
+        GetCredentialException
+    >(context) {
+
+    /** The callback object state, used in the protected handleResponse method. */
+    @VisibleForTesting
+    lateinit var callback: CredentialManagerCallback
+
+    /** The callback requires an executor to invoke it. */
+    @VisibleForTesting lateinit var executor: Executor
+
+    /**
+     * The cancellation signal, which is shuttled around to stop the flow at any moment prior to
+     * returning data.
+     */
+    @VisibleForTesting private var cancellationSignal: CancellationSignal? = null
+
+    @Suppress("deprecation")
+    private val resultReceiver =
+        object : ResultReceiver(Handler(Looper.getMainLooper())) {
+            public override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
+                if (
+                    maybeReportErrorFromResultReceiver(
+                        resultData,
+                        CredentialProviderBaseController.Companion::
+                            getCredentialExceptionTypeToException,
+                        executor,
+                        callback,
+                        cancellationSignal
+                    )
+                ) {
+                    return
+                } else {
+                    handleResponse(
+                        resultData.getInt(ACTIVITY_REQUEST_CODE_TAG),
+                        resultCode,
+                        resultData.getParcelable(RESULT_DATA_TAG)
+                    )
+                }
+            }
+        }
+
+    internal fun handleResponse(uniqueRequestCode: Int, resultCode: Int, data: Intent?) {
+        if (uniqueRequestCode != CONTROLLER_REQUEST_CODE) {
+            Log.w(
+                TAG,
+                "Returned request code $CONTROLLER_REQUEST_CODE which " +
+                    " does not match what was given $uniqueRequestCode"
+            )
+            return
+        }
+
+        if (
+            maybeReportErrorResultCodeGet(
+                resultCode,
+                { s, f -> cancelOrCallbackExceptionOrResult(s, f) },
+                { e -> this.executor.execute { this.callback.onError(e) } },
+                cancellationSignal
+            )
+        ) {
+            return
+        }
+
+        try {
+            val response = IntentHelper.extractGetCredentialResponse(resultCode, data?.extras!!)
+            cancelOrCallbackExceptionOrResult(cancellationSignal) {
+                this.executor.execute {
+                    this.callback.onResult(convertResponseToCredentialManager(response))
+                }
+            }
+        } catch (e: Exception) {
+            val getException = fromGmsException(e)
+            cancelOrCallbackExceptionOrResult(cancellationSignal) {
+                executor.execute { callback.onError(getException) }
+            }
+        }
+    }
+
+    override fun invokePlayServices(
+        request: GetCredentialRequest,
+        callback: CredentialManagerCallback,
+        executor: Executor,
+        cancellationSignal: CancellationSignal?
+    ) {
+        this.cancellationSignal = cancellationSignal
+        this.callback = callback
+        this.executor = executor
+
+        if (CredentialProviderPlayServicesImpl.cancellationReviewer(cancellationSignal)) {
+            return
+        }
+
+        val convertedRequest = this.convertRequestToPlayServices(request)
+        IdentityCredentialManager.getClient(context)
+            .getCredential(convertedRequest)
+            .addOnSuccessListener { result ->
+                if (CredentialProviderPlayServicesImpl.cancellationReviewer(cancellationSignal)) {
+                    return@addOnSuccessListener
+                }
+                val hiddenIntent = Intent(context, IdentityCredentialApiHiddenActivity::class.java)
+                hiddenIntent.flags = Intent.FLAG_ACTIVITY_NO_ANIMATION
+                hiddenIntent.putExtra(
+                    RESULT_RECEIVER_TAG,
+                    toIpcFriendlyResultReceiver(resultReceiver)
+                )
+                hiddenIntent.putExtra(EXTRA_GET_CREDENTIAL_INTENT, result.pendingIntent)
+                context.startActivity(hiddenIntent)
+            }
+            .addOnFailureListener { e ->
+                val getException = fromGmsException(e)
+                cancelOrCallbackExceptionOrResult(cancellationSignal) {
+                    executor.execute { callback.onError(getException) }
+                }
+            }
+    }
+
+    private fun fromGmsException(e: Throwable): GetCredentialException {
+        return when (e) {
+            is com.google.android.gms.identitycredentials.GetCredentialException ->
+                toJetpackGetException(e.type, e.message)
+            is ApiException ->
+                when (e.statusCode) {
+                    CommonStatusCodes.CANCELED -> {
+                        GetCredentialCancellationException(e.message)
+                    }
+                    in retryables -> {
+                        GetCredentialInterruptedException(e.message)
+                    }
+                    else -> {
+                        GetCredentialUnknownException("Get digital credential failed, failure: $e")
+                    }
+                }
+            else -> GetCredentialUnknownException("Get digital credential failed, failure: $e")
+        }
+    }
+
+    public override fun convertRequestToPlayServices(
+        request: GetCredentialRequest
+    ): com.google.android.gms.identitycredentials.GetCredentialRequest {
+        val credOptions =
+            mutableListOf()
+        for (option in request.credentialOptions) {
+            if (option is GetDigitalCredentialOption) {
+                credOptions.add(
+                    com.google.android.gms.identitycredentials.CredentialOption(
+                        option.type,
+                        option.requestData,
+                        option.candidateQueryData,
+                        option.requestJson,
+                        requestType = "",
+                        protocolType = "",
+                    )
+                )
+            }
+        }
+        return com.google.android.gms.identitycredentials.GetCredentialRequest(
+            credOptions,
+            GetCredentialRequest.getRequestMetadataBundle(request),
+            request.origin,
+            ResultReceiver(null) // No-op
+        )
+    }
+
+    public override fun convertResponseToCredentialManager(
+        response: com.google.android.gms.identitycredentials.GetCredentialResponse
+    ): GetCredentialResponse {
+        return GetCredentialResponse(
+            Credential.createFrom(
+                DigitalCredential.TYPE_DIGITAL_CREDENTIAL, // TODO: b/361100869 - use the real type
+                // returned as the response
+                response.credential.data,
+            )
+        )
+    }
+
+    private companion object {
+        private const val TAG = "DigitalCredentialClient"
+    }
+}
diff --git a/credentials/credentials/api/current.txt b/credentials/credentials/api/current.txt
index 50e153f..043c63f 100644
--- a/credentials/credentials/api/current.txt
+++ b/credentials/credentials/api/current.txt
@@ -870,7 +870,6 @@
 
   @RequiresApi(35) public final class BiometricPromptData {
     ctor public BiometricPromptData();
-    ctor public BiometricPromptData();
     ctor public BiometricPromptData(optional androidx.biometric.BiometricPrompt.CryptoObject? cryptoObject);
     ctor public BiometricPromptData(optional androidx.biometric.BiometricPrompt.CryptoObject? cryptoObject, optional int allowedAuthenticators);
     method public int getAllowedAuthenticators();
diff --git a/credentials/credentials/api/restricted_current.txt b/credentials/credentials/api/restricted_current.txt
index 50e153f..043c63f 100644
--- a/credentials/credentials/api/restricted_current.txt
+++ b/credentials/credentials/api/restricted_current.txt
@@ -870,7 +870,6 @@
 
   @RequiresApi(35) public final class BiometricPromptData {
     ctor public BiometricPromptData();
-    ctor public BiometricPromptData();
     ctor public BiometricPromptData(optional androidx.biometric.BiometricPrompt.CryptoObject? cryptoObject);
     ctor public BiometricPromptData(optional androidx.biometric.BiometricPrompt.CryptoObject? cryptoObject, optional int allowedAuthenticators);
     method public int getAllowedAuthenticators();
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialJavaTest.java
new file mode 100644
index 0000000..156e248
--- /dev/null
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialJavaTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2024 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.credentials;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DigitalCredentialJavaTest {
+    private static final String TEST_CREDENTIAL_JSON =
+            "{\"protocol\":{\"preview\":{\"test\":\"val\"}}}";
+    @Test
+    public void typeConstant() {
+        assertThat(DigitalCredential.TYPE_DIGITAL_CREDENTIAL)
+                .isEqualTo("androidx.credentials.TYPE_DIGITAL_CREDENTIAL");
+    }
+
+    @Test
+    public void constructor_emptyCredentialJson_throws() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new DigitalCredential("")
+        );
+    }
+
+
+    @Test
+    public void constructor_invalidCredentialJsonFormat_throws() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new DigitalCredential("hello")
+        );
+    }
+
+    @Test
+    public void constructorAndGetter() {
+        DigitalCredential credential = new DigitalCredential(TEST_CREDENTIAL_JSON);
+        assertThat(credential.getCredentialJson()).isEqualTo(TEST_CREDENTIAL_JSON);
+    }
+
+    @Test
+    public void frameworkConversion_success() {
+        DigitalCredential credential = new DigitalCredential(TEST_CREDENTIAL_JSON);
+        // Add additional data to the request data and candidate query data to make sure
+        // they persist after the conversion
+        Bundle data = credential.getData();
+        String customDataKey = "customRequestDataKey";
+        CharSequence customDataValue = "customRequestDataValue";
+        data.putCharSequence(customDataKey, customDataValue);
+
+        Credential convertedCredential = Credential.createFrom(
+                credential.getType(), data);
+
+        assertThat(convertedCredential).isInstanceOf(DigitalCredential.class);
+        DigitalCredential convertedSubclassCredential = (DigitalCredential) convertedCredential;
+        assertThat(convertedSubclassCredential.getCredentialJson())
+                .isEqualTo(credential.getCredentialJson());
+        assertThat(convertedCredential.getData().getCharSequence(customDataKey))
+                .isEqualTo(customDataValue);
+    }
+}
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialTest.kt
new file mode 100644
index 0000000..fd483df
--- /dev/null
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/DigitalCredentialTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2024 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.credentials
+
+import androidx.credentials.Credential.Companion.createFrom
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DigitalCredentialTest {
+    @Test
+    fun typeConstant() {
+        assertThat(DigitalCredential.TYPE_DIGITAL_CREDENTIAL)
+            .isEqualTo("androidx.credentials.TYPE_DIGITAL_CREDENTIAL")
+    }
+
+    @Test
+    fun constructor_emptyCredentialJson_throws() {
+        assertThrows(IllegalArgumentException::class.java) { DigitalCredential("") }
+    }
+
+    @Test
+    fun constructor_invalidCredentialJsonFormat_throws() {
+        assertThrows(IllegalArgumentException::class.java) { DigitalCredential("hello") }
+    }
+
+    @Test
+    fun constructorAndGetter() {
+        val credential = DigitalCredential(TEST_CREDENTIAL_JSON)
+        assertThat(credential.credentialJson).isEqualTo(TEST_CREDENTIAL_JSON)
+    }
+
+    @Test
+    fun frameworkConversion_success() {
+        val credential = DigitalCredential(TEST_CREDENTIAL_JSON)
+        // Add additional data to the request data and candidate query data to make sure
+        // they persist after the conversion
+        val data = credential.data
+        val customDataKey = "customRequestDataKey"
+        val customDataValue: CharSequence = "customRequestDataValue"
+        data.putCharSequence(customDataKey, customDataValue)
+
+        val convertedCredential = createFrom(credential.type, data)
+
+        assertThat(convertedCredential).isInstanceOf(DigitalCredential::class.java)
+        val convertedSubclassCredential = convertedCredential as DigitalCredential
+        assertThat(convertedSubclassCredential.credentialJson).isEqualTo(credential.credentialJson)
+        assertThat(convertedCredential.data.getCharSequence(customDataKey))
+            .isEqualTo(customDataValue)
+    }
+
+    companion object {
+        private const val TEST_CREDENTIAL_JSON = "{\"protocol\":{\"preview\":{\"test\":\"val\"}}}"
+    }
+}
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionJavaTest.java b/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionJavaTest.java
new file mode 100644
index 0000000..534f36e
--- /dev/null
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionJavaTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 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.credentials;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class GetDigitalCredentialOptionJavaTest {
+    private static final String TEST_REQUEST_JSON =
+            "{\"protocol\":{\"preview\":{\"test\":\"val\"}}}";
+
+    private static final int EXPECTED_PRIORITY =
+            CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR;
+
+    @Test
+    public void constructorAndGetter() {
+        GetDigitalCredentialOption option = new GetDigitalCredentialOption(TEST_REQUEST_JSON);
+
+        assertThat(option.getRequestJson()).isEqualTo(TEST_REQUEST_JSON);
+        assertThat(option.getAllowedProviders()).isEmpty();
+        assertThat(option.isSystemProviderRequired()).isFalse();
+        assertThat(option.isAutoSelectAllowed()).isFalse();
+        assertThat(option.getType()).isEqualTo(DigitalCredential.TYPE_DIGITAL_CREDENTIAL);
+        assertThat(option.getTypePriorityHint()).isEqualTo(EXPECTED_PRIORITY);
+    }
+
+    @Test
+    public void frameworkConversion_success() {
+        GetDigitalCredentialOption option = new GetDigitalCredentialOption(TEST_REQUEST_JSON);
+        // Add additional data to the request data and candidate query data to make sure
+        // they persist after the conversion
+        Bundle requestData = option.getRequestData();
+        String customRequestDataKey = "customRequestDataKey";
+        String customRequestDataValue = "customRequestDataValue";
+        requestData.putString(customRequestDataKey, customRequestDataValue);
+        Bundle candidateQueryData = option.getCandidateQueryData();
+        String customCandidateQueryDataKey = "customRequestDataKey";
+        boolean customCandidateQueryDataValue = true;
+        candidateQueryData.putBoolean(customCandidateQueryDataKey, customCandidateQueryDataValue);
+
+        CredentialOption convertedOption = CredentialOption.createFrom(
+                option.getType(), requestData, candidateQueryData,
+                option.isSystemProviderRequired(), option.getAllowedProviders());
+
+        assertThat(convertedOption).isInstanceOf(GetDigitalCredentialOption.class);
+        GetDigitalCredentialOption actualOption = (GetDigitalCredentialOption) convertedOption;
+        assertThat(actualOption.isAutoSelectAllowed()).isFalse();
+        assertThat(actualOption.getAllowedProviders()).isEmpty();
+        assertThat(actualOption.getRequestJson()).isEqualTo(TEST_REQUEST_JSON);
+        assertThat(convertedOption.getRequestData().getString(customRequestDataKey))
+                .isEqualTo(customRequestDataValue);
+        assertThat(convertedOption.getCandidateQueryData().getBoolean(customCandidateQueryDataKey))
+                .isEqualTo(customCandidateQueryDataValue);
+        assertThat(convertedOption.getTypePriorityHint()).isEqualTo(EXPECTED_PRIORITY);
+    }
+}
diff --git a/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionTest.kt b/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionTest.kt
new file mode 100644
index 0000000..a61b14d
--- /dev/null
+++ b/credentials/credentials/src/androidTest/java/androidx/credentials/GetDigitalCredentialOptionTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 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.credentials
+
+import androidx.credentials.CredentialOption.Companion.createFrom
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class GetDigitalCredentialOptionTest {
+    @Test
+    fun constructorAndGetter() {
+        val option = GetDigitalCredentialOption(TEST_REQUEST_JSON)
+
+        assertThat(option.requestJson).isEqualTo(TEST_REQUEST_JSON)
+        assertThat(option.allowedProviders).isEmpty()
+        assertThat(option.isSystemProviderRequired).isFalse()
+        assertThat(option.isAutoSelectAllowed).isFalse()
+        assertThat(option.type).isEqualTo(DigitalCredential.TYPE_DIGITAL_CREDENTIAL)
+        assertThat(option.typePriorityHint).isEqualTo(EXPECTED_PRIORITY)
+    }
+
+    @Test
+    fun frameworkConversion_success() {
+        val option = GetDigitalCredentialOption(TEST_REQUEST_JSON)
+        // Add additional data to the request data and candidate query data to make sure
+        // they persist after the conversion
+        val requestData = option.requestData
+        val customRequestDataKey = "customRequestDataKey"
+        val customRequestDataValue = "customRequestDataValue"
+        requestData.putString(customRequestDataKey, customRequestDataValue)
+        val candidateQueryData = option.candidateQueryData
+        val customCandidateQueryDataKey = "customRequestDataKey"
+        val customCandidateQueryDataValue = true
+        candidateQueryData.putBoolean(customCandidateQueryDataKey, customCandidateQueryDataValue)
+
+        val convertedOption =
+            createFrom(
+                option.type,
+                requestData,
+                candidateQueryData,
+                option.isSystemProviderRequired,
+                option.allowedProviders
+            )
+
+        assertThat(convertedOption).isInstanceOf(GetDigitalCredentialOption::class.java)
+        val actualOption = convertedOption as GetDigitalCredentialOption
+        assertThat(actualOption.isAutoSelectAllowed).isFalse()
+        assertThat(actualOption.allowedProviders).isEmpty()
+        assertThat(actualOption.requestJson).isEqualTo(TEST_REQUEST_JSON)
+        assertThat(convertedOption.requestData.getString(customRequestDataKey))
+            .isEqualTo(customRequestDataValue)
+        assertThat(convertedOption.candidateQueryData.getBoolean(customCandidateQueryDataKey))
+            .isEqualTo(customCandidateQueryDataValue)
+        assertThat(convertedOption.typePriorityHint).isEqualTo(EXPECTED_PRIORITY)
+    }
+
+    companion object {
+        private const val TEST_REQUEST_JSON = "{\"protocol\":{\"preview\":{\"test\":\"val\"}}}"
+
+        private const val EXPECTED_PRIORITY = CredentialOption.PRIORITY_PASSKEY_OR_SIMILAR
+    }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/Credential.kt b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
index ff80871..b0754c7 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/Credential.kt
@@ -56,6 +56,7 @@
                     PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
                         PublicKeyCredential.createFrom(data)
                     RestoreCredential.TYPE_RESTORE_CREDENTIAL -> RestoreCredential.createFrom(data)
+                    DigitalCredential.TYPE_DIGITAL_CREDENTIAL -> DigitalCredential.createFrom(data)
                     else -> throw FrameworkClassParsingException()
                 }
             } catch (e: FrameworkClassParsingException) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
index 92e17e4..202fdaa 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialOption.kt
@@ -180,6 +180,13 @@
                                 )
                             else -> throw FrameworkClassParsingException()
                         }
+                    DigitalCredential.TYPE_DIGITAL_CREDENTIAL ->
+                        GetDigitalCredentialOption.createFrom(
+                            requestData = requestData,
+                            candidateQueryData = candidateQueryData,
+                            requireSystemProvider = requireSystemProvider,
+                            allowedProviders = allowedProviders,
+                        )
                     else -> throw FrameworkClassParsingException()
                 }
             } catch (e: FrameworkClassParsingException) {
diff --git a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
index ad97445..50ec46d 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/CredentialProviderFactory.kt
@@ -77,7 +77,13 @@
             return tryCreatePreUOemProvider()
         } else if (request is GetCredentialRequest) {
             for (option in request.credentialOptions) {
-                if (option is GetRestoreCredentialOption) {
+                if (option is GetRestoreCredentialOption || option is GetDigitalCredentialOption) {
+                    if (request.credentialOptions.any { it !is GetDigitalCredentialOption }) {
+                        throw IllegalArgumentException(
+                            "`GetDigitalCredentialOption` cannot be" +
+                                " combined with other option types in a single request"
+                        )
+                    }
                     return tryCreatePreUOemProvider()
                 }
             }
diff --git a/credentials/credentials/src/main/java/androidx/credentials/DigitalCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/DigitalCredential.kt
new file mode 100644
index 0000000..4ff5796
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/DigitalCredential.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2024 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.credentials
+
+import android.os.Bundle
+import androidx.annotation.RestrictTo
+import androidx.credentials.internal.FrameworkClassParsingException
+import androidx.credentials.internal.RequestValidationHelper
+
+/**
+ * Represents the user's digital credential, generally used for verification or sign-in purposes.
+ *
+ * @property credentialJson the digital credential in the JSON format; the latest format is defined
+ *   at https://wicg.github.io/digital-credentials/#the-digitalcredential-interface
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class DigitalCredential
+private constructor(
+    val credentialJson: String,
+    data: Bundle,
+) : Credential(TYPE_DIGITAL_CREDENTIAL, data) {
+
+    init {
+        require(RequestValidationHelper.isValidJSON(credentialJson)) {
+            "credentialJson must not be empty, and must be a valid JSON"
+        }
+    }
+
+    /**
+     * Constructs a `DigitalCredential`.
+     *
+     * @param credentialJson the digital credential in the JSON format; the latest format is defined
+     *   at https://wicg.github.io/digital-credentials/#the-digitalcredential-interface
+     * @throws IllegalArgumentException if the `credentialJson` is not a valid json
+     */
+    constructor(
+        credentialJson: String,
+    ) : this(credentialJson, toBundle(credentialJson))
+
+    /** Companion constants / helpers for [DigitalCredential]. */
+    companion object {
+        /** The type value for public key credential related operations. */
+        const val TYPE_DIGITAL_CREDENTIAL: String = "androidx.credentials.TYPE_DIGITAL_CREDENTIAL"
+
+        internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+
+        @JvmStatic
+        fun createFrom(data: Bundle): DigitalCredential {
+            try {
+                val credentialJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+                return DigitalCredential(credentialJson!!, data)
+            } catch (e: Exception) {
+                throw FrameworkClassParsingException()
+            }
+        }
+
+        @JvmStatic
+        fun toBundle(responseJson: String): Bundle {
+            val bundle = Bundle()
+            bundle.putString(BUNDLE_KEY_REQUEST_JSON, responseJson)
+            return bundle
+        }
+    }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/GetDigitalCredentialOption.kt b/credentials/credentials/src/main/java/androidx/credentials/GetDigitalCredentialOption.kt
new file mode 100644
index 0000000..d3a177a
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/GetDigitalCredentialOption.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2024 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.credentials
+
+import android.content.ComponentName
+import android.os.Bundle
+import androidx.annotation.RestrictTo
+import androidx.credentials.internal.FrameworkClassParsingException
+import androidx.credentials.internal.RequestValidationHelper
+
+/**
+ * A request to retrieve the user's digital credential, normally used for verification or sign-in
+ * purpose.
+ *
+ * Note that this option cannot be combined with other types of options in a single
+ * [GetCredentialRequest].
+ *
+ * @property requestJson the request in the JSON format; the latest format is defined at
+ *   https://wicg.github.io/digital-credentials/#the-digitalcredentialrequestoptions-dictionary
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class GetDigitalCredentialOption
+internal constructor(
+    val requestJson: String,
+    requestData: Bundle,
+    candidateQueryData: Bundle,
+    isSystemProviderRequired: Boolean,
+    isAutoSelectAllowed: Boolean,
+    allowedProviders: Set,
+    typePriorityHint: @PriorityHints Int,
+) :
+    CredentialOption(
+        type = DigitalCredential.TYPE_DIGITAL_CREDENTIAL,
+        requestData = requestData,
+        candidateQueryData = candidateQueryData,
+        isSystemProviderRequired = isSystemProviderRequired,
+        isAutoSelectAllowed = isAutoSelectAllowed,
+        allowedProviders = allowedProviders,
+        typePriorityHint = typePriorityHint,
+    ) {
+
+    init {
+        require(RequestValidationHelper.isValidJSON(requestJson)) {
+            "credentialJson must not be empty, and must be a valid JSON"
+        }
+    }
+
+    /**
+     * Constructs a `GetDigitalCredentialOption`.
+     *
+     * Note that this option cannot be combined with other types of options in a single
+     * [GetCredentialRequest].
+     *
+     * @param requestJson the request in the JSON format; the latest format is defined at
+     *   https://wicg.github.io/digital-credentials/#the-digitalcredentialrequestoptions-dictionary
+     * @throws IllegalArgumentException if the `credentialJson` is not a valid json
+     */
+    constructor(
+        requestJson: String
+    ) : this(
+        requestJson = requestJson,
+        requestData = toBundle(requestJson),
+        candidateQueryData = toBundle(requestJson),
+        isSystemProviderRequired = false,
+        isAutoSelectAllowed = false,
+        allowedProviders = emptySet(),
+        typePriorityHint = PRIORITY_PASSKEY_OR_SIMILAR,
+    )
+
+    internal companion object {
+        internal const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+
+        @JvmStatic
+        internal fun toBundle(requestJson: String): Bundle {
+            val bundle = Bundle()
+            bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+            return bundle
+        }
+
+        @JvmStatic
+        internal fun createFrom(
+            requestData: Bundle,
+            candidateQueryData: Bundle,
+            requireSystemProvider: Boolean,
+            allowedProviders: Set,
+        ): GetDigitalCredentialOption {
+            try {
+                val requestJson = requestData.getString(BUNDLE_KEY_REQUEST_JSON)!!
+                return GetDigitalCredentialOption(
+                    requestJson = requestJson,
+                    requestData = requestData,
+                    candidateQueryData = candidateQueryData,
+                    isSystemProviderRequired = requireSystemProvider,
+                    isAutoSelectAllowed =
+                        requestData.getBoolean(BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED, false),
+                    allowedProviders = allowedProviders,
+                    typePriorityHint =
+                        requestData.getInt(
+                            BUNDLE_KEY_TYPE_PRIORITY_VALUE,
+                            PRIORITY_PASSKEY_OR_SIMILAR
+                        ),
+                )
+            } catch (e: Exception) {
+                throw FrameworkClassParsingException()
+            }
+        }
+    }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/internal/ConversionUtils.kt b/credentials/credentials/src/main/java/androidx/credentials/internal/ConversionUtils.kt
index f0bee73..d120681 100644
--- a/credentials/credentials/src/main/java/androidx/credentials/internal/ConversionUtils.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/internal/ConversionUtils.kt
@@ -74,10 +74,8 @@
     return createCredentialData
 }
 
-internal fun toJetpackGetException(
-    errorType: String,
-    errorMsg: CharSequence?
-): GetCredentialException {
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+fun toJetpackGetException(errorType: String, errorMsg: CharSequence?): GetCredentialException {
 
     return when (errorType) {
         android.credentials.GetCredentialException.TYPE_NO_CREDENTIAL ->
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 619c5f9..9c8f089 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -333,3 +333,5 @@
 WARN: Attempt to load key 'java\.correct\.class\.type\.by\.place\.resolve\.scope' for not yet loaded registry
 warning: unable to find kotlin\-stdlib\.jar in the Kotlin home directory\. Pass either '\-no\-stdlib' to prevent adding it to the classpath, or the correct '\-kotlin\-home'
 warning: unable to find kotlin\-script\-runtime\.jar in the Kotlin home directory\. Pass either '\-no\-stdlib' to prevent adding it to the classpath, or the correct '\-kotlin\-home'
+# develocity plugin begign warning, reported back to Gradle
+Failed sysctl call: hw\.nperflevels, Error code: 2
diff --git a/development/validateRefactor.sh b/development/validateRefactor.sh
index 7170a98..1fb6cd2 100755
--- a/development/validateRefactor.sh
+++ b/development/validateRefactor.sh
@@ -32,13 +32,21 @@
 
   Validates that libraries built from the given versions are the same as
   the build outputs built at HEAD. This can be used to validate that a refactor
-  did not change the outputs. If a git treeish is given with no path, the path is considered to be frameworks/support
+  did not change the outputs.
+  If a git treeish is given with no path, the path is considered to be frameworks/support
 
   Example: $0 HEAD^
   Example: $0 prebuilts/androidx/external:HEAD^ frameworks/support:work^
 
-  * A git treeish is what you type when you run 'git checkout '
+    * A git treeish is what you type when you run 'git checkout '
     See also https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddeftree-ishatree-ishalsotreeish .
+
+  You can also supply additional arguments that will be passed through to validateRefactorHelper.py, using -P
+  For example, the baseline arguments that validateRefactorHelper.py accepts.
+  Example: $0 HEAD^ -p agpKmp
+
+  validateRefactor also accepts git treeishes as named arguments using -g
+  Example: $0 -g HEAD^ -p agpKmp
   "
   return 1
 }
@@ -118,27 +126,43 @@
   unzipInPlace "${tempOutPath}/dist/docs-public-0.zip"
 }
 
-oldCommits="$(expandCommitArgs $@)"
-projectPaths="$(getParticipatingProjectPaths $oldCommits)"
-if echo $projectPaths | grep external/dokka >/dev/null; then
-  if [ "$BUILD_DOKKA" == "" ]; then
-    echo "It doesn't make sense to include the external/dokka project without also setting BUILD_DOKKA=true. Did you mean to set BUILD_DOKKA=true?"
-    exit 1
+nonNamedArgs=()
+oldCommits=()
+passThruArgs=()
+while [ $OPTIND -le "$#" ]; do
+  if getopts ":p:g:" opt; then
+    case $opt in
+      \? ) usage;;
+      g ) oldCommits+="$(expandCommitArgs $OPTARG)";;
+      p ) passThruArgs+="$OPTARG";;
+    esac
+    case $OPTARG in
+      -*) usage;;
+    esac
+  else
+    nonNamedArgs+=("${!OPTIND}")
+    ((OPTIND++))
   fi
-fi
-echo old commits: $oldCommits
+done
+
+oldCommits+="$(expandCommitArgs $nonNamedArgs)"
+
+projectPaths="$(getParticipatingProjectPaths $oldCommits)"
 if [ "$oldCommits" == "" ]; then
   usage
 fi
+
 newCommits="$(getCurrentCommits $projectPaths)"
 cd "$supportRoot"
+if [[ $(git update-index --refresh) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi
+if [[ $(git diff-index --quiet HEAD) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi
+echo old commits: $oldCommits
 echo new commits: $newCommits
-
+cd "$supportRoot"
 oldOutPath="${checkoutRoot}/out-old"
 newOutPath="${checkoutRoot}/out-new"
 tempOutPath="${checkoutRoot}/out"
 
-
 rm -rf "$oldOutPath" "$newOutPath" "$tempOutPath"
 
 echo building new commit
@@ -158,10 +182,9 @@
 uncheckout "$projectPaths"
 mv "$tempOutPath" "$oldOutPath"
 
+
 echo
 echo diffing results
-# Don't care about maven-metadata files because they have timestamps in them
-# We might care to know whether .sha1 or .md5 files have changed, but changes in those files will always be accompanied by more meaningful changes in other files, so we don't need to show changes in .sha1 or .md5 files
-# We also don't care about several specific files, either
-echoAndDo diff -r -x "*.md5*" -x "*.sha*" -x "*maven-metadata.xml" -x buildSrc.jar -x jetpad-integration.jar -x "top-of-tree-m2repository-all-0.zip" -x noto-emoji-compat-java.jar -x versionedparcelable-annotation.jar -x dokkaTipOfTreeDocs-0.zip "$oldOutPath/dist" "$newOutPath/dist"
+# This script performs the diff, and filters out known issues and non-issues with baselines
+python development/validateRefactorHelper.py "$passThruArgs"
 echo end of difference
diff --git a/development/validateRefactorHelper.py b/development/validateRefactorHelper.py
new file mode 100644
index 0000000..dcdf3ae
--- /dev/null
+++ b/development/validateRefactorHelper.py
@@ -0,0 +1,197 @@
+#
+#  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.
+#
+"""A helper script for validateRefactor.sh. Should generally not be used directly.
+
+Can be used directly if validateRefactor.sh has already created the out-old & out-new dirs.
+In such a case, it can be run to compare those directories without regenerating them.
+This is generally only useful when updating baselines or iterating on this script itself.
+Takes baseline names as CLI arguments, which may be passed through from validateRefactor.sh.
+
+Typical usage example:
+
+  python validateRefactorHelper.py agpKmp
+"""
+import itertools
+import os
+import shutil
+import subprocess
+import sys
+
+# noto-emoji-compat `bundleinside`s an externally-built with-timestamps jar.
+# classes.jar is compared using `diffuse` instead of unzipping and diffing class files.
+bannedJars = ["-x", "noto-emoji-compat-java.jar", "-x", "classes.jar"]
+# java and json aren"t for unzipping, but the poor exclude-everything-but-jars regex doesn't
+# exclude them. Same for exclude-non-klib and .kt/.knm
+areNotZips = ["-x", r"**\.java", "-x", r"**\.json", "-x", r"**\.kt", "-x", r"**\.knm"]
+# keeps making my regexes fall over :(
+hasNoExtension = ["-x", "manifest", "-x", "module"]
+doNotUnzip = bannedJars + areNotZips + hasNoExtension
+
+def diff(excludes):
+    return popenAndReturn(["diff", "-r", "../../out-old/dist/", "../../out-new/dist/"] + excludes)
+
+def popenAndReturn(args):
+    return subprocess.Popen(args, stdout=subprocess.PIPE).stdout.read().decode("utf-8").split("\n")
+
+# Finds and unzips all files with old/new diff that _do not_ match the argument regex.
+def findFilesMatchingWithDiffAndUnzip(regexThatMatchesEverythingElse):
+    # Exclude all things that are *not* the desired zip type
+    # (because diff doesn"t have an --include, only --exclude).
+    zipsWithDiffs = diff(["-q", "-x", regexThatMatchesEverythingElse] + doNotUnzip)
+    # Take only changed files, not new/deleted ones (the diff there is obvious)
+    zipsWithDiffs = filter(lambda s: s.startswith("Files"), zipsWithDiffs)
+    zipsWithDiffs = map(lambda s: s.split()[1:4:2], zipsWithDiffs)
+    zipsWithDiffs = list(itertools.chain.from_iterable(zipsWithDiffs))  # flatten
+    # And unzip them
+    for filename in zipsWithDiffs:
+        print("unzipping " + filename)
+        # if os.path.exists(filename+".unzipped/"): os.rmdir(filename+".unzipped/")
+        shutil.rmtree(filename+".unzipped/")
+        subprocess.Popen(["unzip", "-qq", "-o", filename, "-d", filename+".unzipped/"])
+
+diffusePath = "../../prebuilts/build-tools/diffuse-0.3.0/bin/diffuse"
+
+def compareWithDiffuse(listOfJars):
+    for jarPath in list(filter(None, listOfJars)):
+        print("jarpath: " + jarPath)
+        newJarPath = jarPath.replace("out-old", "out-new")
+        print(popenAndReturn([diffusePath, "diff", "--jar", jarPath, newJarPath]))
+
+# We might care to know whether .sha1 or .md5 files have changed, but changes in those files will
+# always be accompanied by more meaningful changes in other files, so we don"t need to show changes
+# in .sha1 or .md5 files, or in .module files showing the hashes of other files, or config names.
+excludedHashes = ["-x", "*.md5*", "-x", "*.sha**", "-I", "        \"md5\".*", \
+  "-I", "        \"sha.*", "-I", "        \"size\".*", "-I", "      \"name\".*"]
+# Don"t care about maven-metadata files because they have timestamps in them.
+excludedFiles = ["-x", "*maven-metadata.xml**", "-x", r"**\.knm"]  # temporarily ignore knms
+# Also, ignore files that we already unzipped
+excludedZips = ["-x", "*.zip", "-x", "*.jar", "-x", "*.aar", "-x", "*.apk", "-x", "*.klib"]
+
+# These are baselined changes that we understand and know are no-ops in refactors
+# "Unskippable" changes are multi-line and can't be skipped in `diff`, so post-process
+baselinedChangesForAgpKmp = [
+    # these are new attributes being added
+    """        "org.gradle.libraryelements": "aar",""",
+    """        "org.gradle.jvm.environment": "android",""",
+    """        "org.gradle.jvm.environment": "non-jvm",""",
+    """        "org.gradle.jvm.environment": "standard-jvm",""",
+    # this attribute swap occurs alongside the above new attributes added.
+    # https://chat.google.com/room/AAAAW8qmCIs/4phaNn_gsrc
+    """        "org.jetbrains.kotlin.platform.type": "androidJvm\"""",
+    """        "org.jetbrains.kotlin.platform.type": "jvm\"""",
+    # name-only change; nothing resolves based on names
+    """      "name": "releaseApiElements-published",""",
+    """      "name": "androidApiElements-published",""",
+    """            
actual typealias""",  # open bug in dackka b/339221337
+    # we are switching from our KMP sourcejars solution to the upstream one
+    """        "org.gradle.docstype": "fake-sources",""",
+    """        "org.gradle.docstype": "sources",""",
+]
+unskippableBaselinedChangesForAgpKmp = [
+    """
+<           },
+<           "excludes": [
+<             {
+<               "group": "org.jetbrains.kotlin",
+<               "module": "kotlin-stdlib-common"
+<             },
+<             {
+<               "group": "org.jetbrains.kotlin",
+<               "module": "kotlin-test-common"
+<             },
+<             {
+<               "group": "org.jetbrains.kotlin",
+<               "module": "kotlin-test-annotations-common"
+<             }
+<           ]
+---
+>           }
+""",
+"""
+<       
+<         
+<           org.jetbrains.kotlin
+<           kotlin-stdlib-common
+<         
+<         
+<           org.jetbrains.kotlin
+<           kotlin-test-common
+<         
+<         
+<           org.jetbrains.kotlin
+<           kotlin-test-annotations-common
+<         
+<       
+"""
+]
+
+baselinedChanges = []
+unskippableBaselinedChanges = []
+arguments = sys.argv[1:]
+if "agpKmp" in arguments:
+    arguments.remove("agpKmp")
+    print("IGNORING DIFF FOR agpKmp")
+    baselinedChanges += baselinedChangesForAgpKmp
+    unskippableBaselinedChanges += unskippableBaselinedChangesForAgpKmp
+if arguments:
+    print("invalid argument(s) for validateRefactorHelper: " + ", ".join(arguments))
+    print("currently recognized arguments: agpKmp")
+    exit()
+
+# interleave "-I" to tell diffutils to 'I'gnore the baselined lines
+baselinedChanges = list(itertools.chain.from_iterable(zip(["-I"]*99, baselinedChanges)))
+
+# post-process the diff output to remove multi-line changes that can't be excluded in `diff` itself
+def filterOutUnskippableBaselinedChanges(inputString):
+    result = inputString
+    for toRemove in unskippableBaselinedChanges:
+        i = result.find(toRemove)
+        while (i != -1):
+            j = result.rfind("\n", 0, i-2)  # also find and remove previous line e.g. 82,96c70
+            result = result[:j+1] + result[i+len(toRemove):]
+            i = result.find(toRemove)
+    #remove all "diff -r ..." header lines that no longer have content due to baselining
+    result = result.split("\n")
+    nRemoved = 0
+    for i in range(len(result)):  # check for consecutive `diff -r` lines: the first has no content
+        if not result[i-nRemoved].startswith("diff -r "): continue
+        if not result[i+1-nRemoved].startswith("diff -r "): continue
+        del result[i]
+        nRemoved+=1
+    if not result[-1]: del result[-1]  # remove possible ending blank line
+    if result[-1].startswith("diff -r "): del result[-1]  # terminal `diff -r` line: has no content
+    return "\n".join(result)
+
+# print(baselinedChanges)
+
+# Find all zip files with a diff, e.g. the tip-of-tree-repository file, and maybe the docs zip
+# findFilesMatchingWithDiffAndUnzip(r"**\.[^z][a-z]*")
+# Find all aar and apk files with a diff. The proper regex would be `.*\..*[^akpr]+.*`, but it
+# doesn"t work in difftools exclude's very limited regex syntax.
+findFilesMatchingWithDiffAndUnzip(r"**\.[^a][a-z]*")
+# Find all jars and klibs and unzip them (comes after because they could be inside aars/apks).
+findFilesMatchingWithDiffAndUnzip(r"**\.[^j][a-z]*")
+findFilesMatchingWithDiffAndUnzip(r"**\.[^k][a-z]*")
+# now find all diffs in classes.jars
+classesJarsWithDiffs = popenAndReturn(["find", "../../out-old/dist/", "-name", "classes.jar"])
+print("classes.jar s: " + str(classesJarsWithDiffs))
+compareWithDiffuse(classesJarsWithDiffs)
+# Now find all diffs in non-zipped files
+finalExcludes = excludedHashes + excludedFiles + excludedZips + baselinedChanges
+finalDiff = "\n".join(diff(finalExcludes))
+finalDiff = filterOutUnskippableBaselinedChanges(finalDiff)
+print(finalDiff)
+
diff --git a/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/AndroidFragmentTest.kt b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/AndroidFragmentTest.kt
index ac229eb..a1369c7 100644
--- a/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/AndroidFragmentTest.kt
+++ b/fragment/fragment-compose/src/androidTest/java/androidx/fragment/compose/AndroidFragmentTest.kt
@@ -33,12 +33,14 @@
 import androidx.fragment.app.Fragment
 import androidx.fragment.compose.test.EmptyTestActivity
 import androidx.fragment.compose.test.R
+import androidx.lifecycle.Lifecycle
 import androidx.test.espresso.Espresso.onView
 import androidx.test.espresso.assertion.ViewAssertions.matches
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -98,6 +100,68 @@
     }
 
     @Test
+    fun addAfterStateSaved() {
+        lateinit var number: MutableState
+        testRule.setContent {
+            number = remember { mutableStateOf(0) }
+            if (number.value > 0) {
+                AndroidFragment()
+            }
+        }
+
+        testRule.activityRule.scenario.moveToState(Lifecycle.State.CREATED)
+
+        testRule.runOnIdle { number.value = 1 }
+
+        testRule.waitForIdle()
+
+        testRule.activityRule.scenario.moveToState(Lifecycle.State.RESUMED)
+
+        onView(withText("Show me on Screen")).check(matches(isDisplayed()))
+
+        testRule.runOnIdle { number.value = 0 }
+
+        testRule.waitForIdle()
+
+        // Validate that the fragment was removed
+        val fragment =
+            testRule.activity.supportFragmentManager.fragments.firstOrNull {
+                it is FragmentForCompose
+            }
+        assertThat(fragment).isNull()
+    }
+
+    @Test
+    fun addAndRemoveAfterStateSaved() {
+        lateinit var number: MutableState
+        testRule.setContent {
+            number = remember { mutableStateOf(0) }
+            if (number.value > 0) {
+                AndroidFragment()
+            }
+        }
+
+        testRule.activityRule.scenario.moveToState(Lifecycle.State.CREATED)
+
+        testRule.runOnIdle { number.value = 1 }
+
+        testRule.waitForIdle()
+
+        testRule.runOnIdle { number.value = 0 }
+
+        testRule.waitForIdle()
+
+        testRule.activityRule.scenario.moveToState(Lifecycle.State.RESUMED)
+
+        // Validate that the fragment was removed
+        val fragment =
+            testRule.activity.supportFragmentManager.fragments.firstOrNull {
+                it is FragmentForCompose
+            }
+        assertThat(fragment).isNull()
+    }
+
+    @Test
     fun recomposeInsideKey() {
 
         lateinit var number: MutableState
diff --git a/fragment/fragment-compose/src/main/java/androidx/fragment/compose/AndroidFragment.kt b/fragment/fragment-compose/src/main/java/androidx/fragment/compose/AndroidFragment.kt
index 5d9884b..7d455e9 100644
--- a/fragment/fragment-compose/src/main/java/androidx/fragment/compose/AndroidFragment.kt
+++ b/fragment/fragment-compose/src/main/java/androidx/fragment/compose/AndroidFragment.kt
@@ -30,6 +30,8 @@
 import androidx.fragment.app.FragmentContainerView
 import androidx.fragment.app.FragmentManager
 import androidx.fragment.app.commitNow
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
 
 /**
  * Allows for adding a [Fragment] directly into Compose. It creates a fragment of the given class
@@ -93,6 +95,7 @@
     )
 
     DisposableEffect(fragmentManager, clazz, fragmentState) {
+        var removeEvenIfStateIsSaved = false
         val fragment =
             fragmentManager.findFragmentById(container.id)
                 ?: fragmentManager.fragmentFactory
@@ -100,18 +103,42 @@
                     .apply {
                         setInitialSavedState(fragmentState.state.value)
                         setArguments(arguments)
-                        fragmentManager
-                            .beginTransaction()
-                            .setReorderingAllowed(true)
-                            .add(container, this, "$hashKey")
-                            .commitNow()
+                        val transaction =
+                            fragmentManager
+                                .beginTransaction()
+                                .setReorderingAllowed(true)
+                                .add(container, this, "$hashKey")
+                        if (fragmentManager.isStateSaved) {
+                            // If the state is saved when we add the fragment,
+                            // we want to remove the Fragment in onDispose
+                            // if isStateSaved never becomes true for the lifetime
+                            // of this AndroidFragment - we use a LifecycleObserver
+                            // on the Fragment as a proxy for that signal
+                            removeEvenIfStateIsSaved = true
+                            lifecycle.addObserver(
+                                object : DefaultLifecycleObserver {
+                                    override fun onStart(owner: LifecycleOwner) {
+                                        removeEvenIfStateIsSaved = false
+                                        lifecycle.removeObserver(this)
+                                    }
+                                }
+                            )
+                            transaction.commitNowAllowingStateLoss()
+                        } else {
+                            transaction.commitNow()
+                        }
                     }
         fragmentManager.onContainerAvailable(container)
         @Suppress("UNCHECKED_CAST") updateCallback.value(fragment as T)
         onDispose {
             val state = fragmentManager.saveFragmentInstanceState(fragment)
             fragmentState.state.value = state
-            if (!fragmentManager.isStateSaved) {
+            if (removeEvenIfStateIsSaved) {
+                // The Fragment was added when the state was saved and
+                // isStateSaved never became true for the lifetime of this
+                // AndroidFragment, so we unconditionally remove it here
+                fragmentManager.commitNow(allowStateLoss = true) { remove(fragment) }
+            } else if (!fragmentManager.isStateSaved) {
                 // If the state isn't saved, that means that some state change
                 // has removed this Composable from the hierarchy
                 fragmentManager.commitNow { remove(fragment) }
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PredictiveBackTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PredictiveBackTest.kt
index f9ef07b..340f50b 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PredictiveBackTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PredictiveBackTest.kt
@@ -114,4 +114,30 @@
             assertThat(fm.backStackEntryCount).isEqualTo(0)
         }
     }
+
+    @Test
+    fun backOnNoRecordTest() {
+        withUse(ActivityScenario.launch(SimpleContainerActivity::class.java)) {
+            val fm = withActivity { supportFragmentManager }
+
+            val fragment1 = StrictViewFragment()
+
+            fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment1, "1")
+                .setReorderingAllowed(true)
+                .commit()
+            executePendingTransactions()
+
+            val dispatcher = withActivity { onBackPressedDispatcher }
+
+            // We need a pending commit that doesn't include a fragment to mimic calling
+            // system back while commit is pending.
+            fm.beginTransaction().commit()
+
+            dispatcher.dispatchOnBackStarted(BackEventCompat(0.1F, 0.1F, 0.1F, BackEvent.EDGE_LEFT))
+            withActivity { dispatcher.onBackPressed() }
+
+            assertThat(fm.backStackEntryCount).isEqualTo(0)
+        }
+    }
 }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index e3d35ae..15ce216 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -2595,6 +2595,16 @@
 
     boolean prepareBackStackState(@NonNull ArrayList records,
             @NonNull ArrayList isRecordPop) {
+        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+            Log.v(
+                    TAG, "FragmentManager has the following pending actions inside of "
+                            + "prepareBackStackState: " + mPendingActions
+            );
+        }
+        if (mBackStack.isEmpty()) {
+            Log.i(TAG, "Ignoring call to start back stack pop because the back stack is empty.");
+            return false;
+        }
         // The transitioning record is the last one on the back stack.
         mTransitioningOp = mBackStack.get(mBackStack.size() - 1);
         // Mark all fragments in the record as transitioning
diff --git a/glance/glance-appwidget/src/main/res/values-fa/strings.xml b/glance/glance-appwidget/src/main/res/values-fa/strings.xml
index 5dd49dc..313a5b7 100644
--- a/glance/glance-appwidget/src/main/res/values-fa/strings.xml
+++ b/glance/glance-appwidget/src/main/res/values-fa/strings.xml
@@ -17,7 +17,7 @@
 
 
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    "‏""خطا در ابزارک برنامه Glance"
+    "‏""خطا در ابزاره برنامه Glance"
     "‏بااستفاده از ""adb logcat"" و جستجوی ""GlanceAppWidget""، خطا را به‌طور دقیق بررسی کنید"
     "محتوا نشان داده نشد"
 
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 90e4eb5af..0dccba0 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -57,7 +57,7 @@
 ktfmt = "0.50"
 leakcanary = "2.13"
 media3 = "1.1.0"
-metalava = "1.0.0-alpha11"
+metalava = "1.0.0-alpha12"
 mockito = "2.25.0"
 moshi = "1.13.0"
 node = "16.20.2"
diff --git a/ink/ink-brush/api/current.txt b/ink/ink-brush/api/current.txt
index c10c574..6d92f23 100644
--- a/ink/ink-brush/api/current.txt
+++ b/ink/ink-brush/api/current.txt
@@ -1,12 +1,7 @@
 // Signature format: 4.0
 package androidx.ink.brush {
 
-  public final class Brush {
-    ctor public Brush(long color, float size);
-    method public long getColor();
-    method public float getSize();
-    property public final long color;
-    property public final float size;
+  @SuppressCompatibility @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.ERROR) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface ExperimentalInkCustomBrushApi {
   }
 
 }
diff --git a/ink/ink-brush/api/restricted_current.txt b/ink/ink-brush/api/restricted_current.txt
index c10c574..6d92f23 100644
--- a/ink/ink-brush/api/restricted_current.txt
+++ b/ink/ink-brush/api/restricted_current.txt
@@ -1,12 +1,7 @@
 // Signature format: 4.0
 package androidx.ink.brush {
 
-  public final class Brush {
-    ctor public Brush(long color, float size);
-    method public long getColor();
-    method public float getSize();
-    property public final long color;
-    property public final float size;
+  @SuppressCompatibility @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.ERROR) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface ExperimentalInkCustomBrushApi {
   }
 
 }
diff --git a/ink/ink-brush/build.gradle b/ink/ink-brush/build.gradle
index 3beaaaa..1137891 100644
--- a/ink/ink-brush/build.gradle
+++ b/ink/ink-brush/build.gradle
@@ -27,12 +27,20 @@
 
 plugins {
     id("AndroidXPlugin")
-    id("com.android.library")
 }
 
 androidXMultiplatform {
-  android()
   jvm()
+  androidLibrary {
+    namespace = "androidx.ink.brush"
+    withAndroidTestOnDeviceBuilder {
+      it.compilationName = "instrumentedTest"
+      it.defaultSourceSetName = "androidInstrumentedTest"
+      it.sourceSetTreeName = "test"
+    }
+    compileSdk = 35
+    aarMetadata.minCompileSdk = 35
+  }
 
   defaultPlatform(PlatformIdentifier.JVM)
 
@@ -47,13 +55,17 @@
         implementation(libs.kotlinStdlib)
         api(libs.androidx.annotation)
         implementation(project(":collection:collection"))
+        implementation(project(":ink:ink-geometry"))
+        implementation(project(":ink:ink-nativeloader"))
       }
     }
 
     jvmAndroidTest {
       dependsOn(commonTest)
       dependencies {
+        implementation(libs.junit)
         implementation(libs.kotlinTest)
+        implementation(libs.truth)
       }
     }
 
@@ -64,7 +76,12 @@
     androidInstrumentedTest {
       dependsOn(jvmAndroidTest)
       dependencies {
+        implementation(libs.testExtJunit)
+        implementation(libs.testRules)
         implementation(libs.testRunner)
+        implementation(libs.espressoCore)
+        implementation(libs.junit)
+        implementation(libs.truth)
       }
     }
 
@@ -78,11 +95,6 @@
   }
 }
 
-android {
-    compileSdk 35
-    namespace = "androidx.ink.brush"
-}
-
 androidx {
     name = "Ink Brush"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/ink/ink-brush/lint-baseline.xml b/ink/ink-brush/lint-baseline.xml
new file mode 100644
index 0000000..73ba869
--- /dev/null
+++ b/ink/ink-brush/lint-baseline.xml
@@ -0,0 +1,13 @@
+
+
+
+    
+        id="Range"
+        message="Expected length ≥ 1 (was 0)"
+        errorLine1="            Rgb("", FloatArray(6), WhitePoint(0f, 0f), sIdentity, sIdentity, 0.0f, 1.0f)"
+        errorLine2="                ~~">
+        
+            file="src/jvmAndroidTest/kotlin/androidx/ink/brush/color/ColorSpaceTest.kt"/>
+    
+
+
diff --git a/ink/ink-brush/src/androidInstrumentedTest/kotlin/androidx/ink/brush/BrushExtensionsTest.kt b/ink/ink-brush/src/androidInstrumentedTest/kotlin/androidx/ink/brush/BrushExtensionsTest.kt
new file mode 100644
index 0000000..bf2034e
--- /dev/null
+++ b/ink/ink-brush/src/androidInstrumentedTest/kotlin/androidx/ink/brush/BrushExtensionsTest.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import android.graphics.Color as AndroidColor
+import android.graphics.ColorSpace as AndroidColorSpace
+import android.os.Build
+import androidx.annotation.ColorLong
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(AndroidJUnit4::class)
+class BrushExtensionsTest {
+    private val displayP3 = AndroidColorSpace.get(AndroidColorSpace.Named.DISPLAY_P3)
+    private val adobeRgb = AndroidColorSpace.get(AndroidColorSpace.Named.ADOBE_RGB)
+
+    private val testColor = AndroidColor.valueOf(0.4f, 0.6f, 0.8f, 0.2f, displayP3)
+    @ColorLong private val testColorLong = testColor.pack()
+
+    @OptIn(ExperimentalInkCustomBrushApi::class)
+    private val testFamily = BrushFamily(uri = "/brush-family:pencil")
+
+    @Test
+    fun brushGetAndroidColor_getsCorrectColor() {
+        val brush = Brush.withColorLong(testFamily, testColorLong, 1f, 1f)
+
+        // Note that expectedColor is not necessarily the same as testColor, because of precision
+        // loss
+        // when converting from testColor to testColorLong (which is necessary, because Brush stores
+        // the
+        // color internally as a ColorLong anyway).
+        val expectedColor = AndroidColor.valueOf(testColorLong)
+        assertThat(brush.getAndroidColor()).isEqualTo(expectedColor)
+    }
+
+    @Test
+    fun brushCopyWithAndroidColor_setsColor() {
+        val brush = Brush.withColorIntArgb(testFamily, 0x4499bb66, 1f, 1f)
+
+        val newBrush = brush.copyWithAndroidColor(color = testColor)
+
+        assertThat(newBrush.family).isEqualTo(brush.family)
+        assertThat(newBrush.colorLong).isEqualTo(testColorLong)
+        assertThat(newBrush.size).isEqualTo(brush.size)
+        assertThat(newBrush.epsilon).isEqualTo(brush.epsilon)
+    }
+
+    @OptIn(ExperimentalInkCustomBrushApi::class)
+    @Test
+    fun brushCopyWithAndroidColor_andOtherChangedValues_createsBrushWithColor() {
+        val brush = Brush.withColorIntArgb(testFamily, 0x4499bb66, 1f, 1f)
+
+        val newBrush =
+            brush.copyWithAndroidColor(
+                color = testColor,
+                family = BrushFamily(),
+                size = 2f,
+                epsilon = 0.2f,
+            )
+
+        assertThat(newBrush.family).isEqualTo(BrushFamily())
+        assertThat(newBrush.colorLong).isEqualTo(testColorLong)
+        assertThat(newBrush.size).isEqualTo(2f)
+        assertThat(newBrush.epsilon).isEqualTo(0.2f)
+    }
+
+    @Test
+    fun brushCopyWithAndroidColor_withUnsupportedColorSpace_setsConvertedColor() {
+        val brush = Brush.withColorIntArgb(testFamily, 0x4499bb66, 1f, 1f)
+
+        val newColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val newBrush = brush.copyWithAndroidColor(color = newColor)
+
+        // newColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(newColor.pack()).convert(displayP3)
+        assertThat(newBrush.colorLong).isEqualTo(expectedColor.pack())
+    }
+
+    @Test
+    fun brushBuilderAndroidColor_setsColor() {
+        val brush =
+            Brush.builder()
+                .setFamily(testFamily)
+                .setAndroidColor(testColor)
+                .setSize(1f)
+                .setEpsilon(1f)
+                .build()
+
+        assertThat(brush.colorLong).isEqualTo(testColorLong)
+    }
+
+    @Test
+    fun brushBuilderAndroidColor_withUnsupportedColorSpace_setsConvertedColor() {
+        val unsupportedColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val brush =
+            Brush.builder()
+                .setFamily(testFamily)
+                .setAndroidColor(unsupportedColor)
+                .setSize(1f)
+                .setEpsilon(1f)
+                .build()
+
+        // unsupportedColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(unsupportedColor.pack()).convert(displayP3)
+        assertThat(brush.colorLong).isEqualTo(expectedColor.pack())
+    }
+
+    @Test
+    fun brushWithAndroidColor_createsBrushWithColor() {
+        val brush = Brush.withAndroidColor(testFamily, testColor, 1f, 1f)
+        assertThat(brush.colorLong).isEqualTo(testColorLong)
+    }
+
+    @Test
+    fun brushWithAndroidColor_withUnsupportedColorSpace_createsBrushWithConvertedColor() {
+        val unsupportedColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val brush = Brush.withAndroidColor(testFamily, unsupportedColor, 1f, 1f)
+
+        // unsupportedColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(unsupportedColor.pack()).convert(displayP3)
+        assertThat(brush.colorLong).isEqualTo(expectedColor.pack())
+    }
+
+    @Test
+    fun brushUtilGetAndroidColor_getsCorrectColor() {
+        val brush = Brush.withColorLong(testFamily, testColorLong, 1f, 1f)
+
+        // Note that expectedColor is not necessarily the same as testColor, because of precision
+        // loss
+        // when converting from testColor to testColorLong.
+        val expectedColor = AndroidColor.valueOf(testColorLong)
+        assertThat(BrushUtil.getAndroidColor(brush)).isEqualTo(expectedColor)
+    }
+
+    @Test
+    fun brushUtilToBuilderWithAndroidColor_setsColor() {
+        val brush = Brush.withColorIntArgb(testFamily, 0x4499bb66, 2f, 0.2f)
+
+        val newBrush = BrushUtil.toBuilderWithAndroidColor(brush, testColor).build()
+
+        assertThat(newBrush.colorLong).isEqualTo(testColorLong)
+        assertThat(brush.family).isEqualTo(testFamily)
+        assertThat(brush.size).isEqualTo(2f)
+        assertThat(brush.epsilon).isEqualTo(0.2f)
+    }
+
+    @Test
+    fun brushUtilToBuilderWithAndroidColor_withUnsupportedColorSpace_setsConvertedColor() {
+        val brush = Brush.withColorIntArgb(testFamily, 0x4499bb66, 2f, 0.2f)
+
+        val unsupportedColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val newBrush = BrushUtil.toBuilderWithAndroidColor(brush, unsupportedColor).build()
+
+        // unsupportedColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(unsupportedColor.pack()).convert(displayP3)
+        assertThat(newBrush.colorLong).isEqualTo(expectedColor.pack())
+
+        assertThat(brush.family).isEqualTo(testFamily)
+        assertThat(brush.size).isEqualTo(2f)
+        assertThat(brush.epsilon).isEqualTo(0.2f)
+    }
+
+    @Test
+    fun brushUtilMakeBuilderWithAndroidColor_setsColor() {
+        val brush =
+            BrushUtil.makeBuilderWithAndroidColor(testColor)
+                .setFamily(testFamily)
+                .setSize(2f)
+                .setEpsilon(0.2f)
+                .build()
+
+        assertThat(brush.family).isEqualTo(testFamily)
+        assertThat(brush.colorLong).isEqualTo(testColorLong)
+        assertThat(brush.size).isEqualTo(2f)
+        assertThat(brush.epsilon).isEqualTo(0.2f)
+    }
+
+    @Test
+    fun brushUtilMakeBuilderAndroidColor_withUnsupportedColorSpace_setsConvertedColor() {
+        val unsupportedColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val brush =
+            BrushUtil.makeBuilderWithAndroidColor(unsupportedColor)
+                .setFamily(testFamily)
+                .setSize(2f)
+                .setEpsilon(0.2f)
+                .build()
+
+        // unsupportedColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(unsupportedColor.pack()).convert(displayP3)
+        assertThat(brush.colorLong).isEqualTo(expectedColor.pack())
+    }
+
+    @Test
+    fun brushUtilMakeBrushWithAndroidColor_createsBrushWithColor() {
+        val brush = BrushUtil.makeBrushWithAndroidColor(testFamily, testColor, 1f, 1f)
+        assertThat(brush.colorLong).isEqualTo(testColorLong)
+    }
+
+    @Test
+    fun brushUtilMakeBrushWithAndroidColor_withUnsupportedColorSpace_createsBrushWithConvertedColor() {
+        val unsupportedColor = AndroidColor.valueOf(0.6f, 0.7f, 0.4f, 0.3f, adobeRgb)
+        val brush = BrushUtil.makeBrushWithAndroidColor(testFamily, unsupportedColor, 1f, 1f)
+
+        // unsupportedColor gets converted to ColorLong (losing precision) and then to Display P3.
+        val expectedColor = AndroidColor.valueOf(unsupportedColor.pack()).convert(displayP3)
+        assertThat(brush.colorLong).isEqualTo(expectedColor.pack())
+    }
+}
diff --git a/ink/ink-brush/src/androidMain/kotlin/androidx/ink/brush/BrushExtensions.android.kt b/ink/ink-brush/src/androidMain/kotlin/androidx/ink/brush/BrushExtensions.android.kt
new file mode 100644
index 0000000..fe64f8cd
--- /dev/null
+++ b/ink/ink-brush/src/androidMain/kotlin/androidx/ink/brush/BrushExtensions.android.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+
+package androidx.ink.brush
+
+import android.graphics.Color as AndroidColor
+import android.os.Build
+import androidx.annotation.CheckResult
+import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
+
+/**
+ * The brush color as an [android.graphics.Color] instance, which can express colors in several
+ * different color spaces. sRGB and Display P3 are supported; a color in any other color space will
+ * be converted to Display P3.
+ */
+@JvmSynthetic
+@CheckResult
+@RequiresApi(Build.VERSION_CODES.O)
+public fun Brush.getAndroidColor(): AndroidColor = BrushUtil.getAndroidColor(this)
+
+/**
+ * Creates a copy of `this` [Brush] and allows named properties to be altered while keeping the rest
+ * unchanged. The color is specified as an [android.graphics.Color] instance, which can encode
+ * several different color spaces. sRGB and Display P3 are supported; a color in any other color
+ * space will be converted to Display P3.
+ */
+@JvmSynthetic
+@CheckResult
+@RequiresApi(Build.VERSION_CODES.O)
+public fun Brush.copyWithAndroidColor(
+    color: AndroidColor,
+    family: BrushFamily = this.family,
+    size: Float = this.size,
+    epsilon: Float = this.epsilon,
+): Brush = copyWithColorLong(family, color.pack(), size, epsilon)
+
+/**
+ * Set the color on a [Brush.Builder] as an [android.graphics.Color] instance. sRGB and Display P3
+ * are supported; a color in any other color space will be converted to Display P3.
+ */
+@JvmSynthetic
+@CheckResult
+@RequiresApi(Build.VERSION_CODES.O)
+public fun Brush.Builder.setAndroidColor(color: AndroidColor): Brush.Builder =
+    setColorLong(color.pack())
+
+/**
+ * Returns a new [Brush] with the color specified by an [android.graphics.Color] instance, which can
+ * encode several different color spaces. sRGB and Display P3 are supported; a color in any other
+ * color space will be converted to Display P3.
+ */
+@JvmSynthetic
+@CheckResult
+@RequiresApi(Build.VERSION_CODES.O)
+public fun Brush.Companion.withAndroidColor(
+    family: BrushFamily,
+    color: AndroidColor,
+    size: Float,
+    epsilon: Float,
+): Brush = BrushUtil.makeBrushWithAndroidColor(family, color, size, epsilon)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+public object BrushUtil {
+
+    /**
+     * The brush color as an [android.graphics.Color] instance, which can express colors in several
+     * different color spaces. sRGB and Display P3 are supported; a color in any other color space
+     * will be converted to Display P3.
+     */
+    @JvmStatic
+    @CheckResult
+    @RequiresApi(Build.VERSION_CODES.O)
+    public fun getAndroidColor(brush: Brush): AndroidColor = AndroidColor.valueOf(brush.colorLong)
+
+    /**
+     * Returns a [Brush.Builder] with values set equivalent to [brush] and the color specified by an
+     * [android.graphics.Color] instance, which can encode several different color spaces. sRGB and
+     * Display P3 are supported; a color in any other color space will be converted to Display P3.
+     * Java developers, use the returned builder to build a copy of a Brush. Kotlin developers, see
+     * [copyWithAndroidColor] method.
+     */
+    @JvmStatic
+    @CheckResult
+    @RequiresApi(Build.VERSION_CODES.O)
+    public fun toBuilderWithAndroidColor(brush: Brush, color: AndroidColor): Brush.Builder =
+        brush.toBuilder().setAndroidColor(color)
+
+    /**
+     * Returns a new [Brush.Builder] with the color specified by an [android.graphics.Color]
+     * instance, which can encode several different color spaces. sRGB and Display P3 are supported;
+     * a color in any other color space will be converted to Display P3.
+     */
+    @JvmStatic
+    @CheckResult
+    @RequiresApi(Build.VERSION_CODES.O)
+    public fun makeBuilderWithAndroidColor(color: AndroidColor): Brush.Builder =
+        Brush.Builder().setAndroidColor(color)
+
+    /**
+     * Returns a new [Brush] with the color specified by an [android.graphics.Color] instance, which
+     * can encode several different color spaces. sRGB and Display P3 are supported; a color in any
+     * other color space will be converted to Display P3.
+     */
+    @JvmStatic
+    @CheckResult
+    @RequiresApi(Build.VERSION_CODES.O)
+    public fun makeBrushWithAndroidColor(
+        family: BrushFamily,
+        color: AndroidColor,
+        size: Float,
+        epsilon: Float,
+    ): Brush = Brush.withColorLong(family, color.pack(), size, epsilon)
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/Brush.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/Brush.kt
index e1d6502..d1ff030 100644
--- a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/Brush.kt
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/Brush.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -16,20 +16,366 @@
 
 package androidx.ink.brush
 
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorLong
+import androidx.annotation.FloatRange
+import androidx.annotation.RestrictTo
 import androidx.ink.brush.color.Color as ComposeColor
+import androidx.ink.brush.color.toArgb
+import androidx.ink.nativeloader.NativeLoader
+import kotlin.Float
+import kotlin.jvm.JvmStatic
 
 /**
  * Defines how stroke inputs are interpreted to create the visual representation of a stroke.
  *
- * A [Brush] completely describes how inputs are used to create stroke meshes, and how those meshes
- * should be drawn by stroke renderers.
- *
- * Note: This is a placeholder implementation/API until the real code is migrated here.
- *
- * @param color The color of the stroke.
- * @param size The overall thickness of strokes created with a given brush, in the same units as the
- *   stroke coordinate system.
+ * The type completely describes how inputs are used to create stroke meshes, and how those meshes
+ * should be drawn by stroke renderers. In an analogous way to "font" and "font family", a [Brush]
+ * can be considered an instance of a [BrushFamily] with a particular [color], [size], and an extra
+ * parameter controlling visual fidelity, called [epsilon].
  */
-public class Brush(public val color: Long, public val size: Float) {
-    private val colorObj = ComposeColor(color.toULong())
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+public class Brush
+internal constructor(
+    /** The [BrushFamily] for this brush. See [StockBrushes] for available [BrushFamily] values. */
+    public val family: BrushFamily,
+    composeColor: ComposeColor,
+    /**
+     * The overall thickness of strokes created with a given brush, in the same units as the stroke
+     * coordinate system. This must be at least as big as [epsilon].
+     */
+    @FloatRange(
+        from = 0.0,
+        fromInclusive = false,
+        to = Double.POSITIVE_INFINITY,
+        toInclusive = false
+    )
+    public val size: Float,
+    /**
+     * The smallest distance for which two points should be considered visually distinct for stroke
+     * generation geometry purposes. Effectively, it is the visual fidelity of strokes created with
+     * this brush, where any (lack of) visual fidelity can be observed by a user the further zoomed
+     * in they are on the stroke. Lower values of [epsilon] result in higher fidelity strokes at the
+     * cost of somewhat higher memory usage. This value, like [size], is in the same units as the
+     * stroke coordinate system. A size of 0.1 physical pixels at the default zoom level is a good
+     * starting point that can tolerate a reasonable amount of zooming in with high quality visual
+     * results.
+     */
+    @FloatRange(
+        from = 0.0,
+        fromInclusive = false,
+        to = Double.POSITIVE_INFINITY,
+        toInclusive = false
+    )
+    public val epsilon: Float,
+) {
+
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public val composeColor: ComposeColor = composeColor.toColorInInkSupportedColorSpace()
+
+    /**
+     * The default color of a [Brush] is pure black. To set a custom color, use [withColorLong] or
+     * [withColorIntArgb].
+     */
+    public constructor(
+        family: BrushFamily,
+        size: Float,
+        epsilon: Float,
+    ) : this(family, DEFAULT_COMPOSE_COLOR, size, epsilon)
+
+    /**
+     * The brush color as a [ColorLong], which can express colors in several different color spaces.
+     * sRGB and Display P3 are supported; a color in any other color space will be converted to
+     * Display P3.
+     */
+    public val colorLong: Long
+        @ColorLong get(): Long = composeColor.value.toLong()
+
+    /**
+     * The brush color as a [ColorInt], which can only express colors in the sRGB color space. For
+     * clients that want to support wide-gamut colors, use [colorLong].
+     */
+    public val colorInt: Int
+        @ColorInt get(): Int = composeColor.toArgb()
+
+    /** A handle to the underlying native [Brush] object. */
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public val nativePointer: Long =
+        nativeCreateBrush(
+            family.nativePointer,
+            this.composeColor.red,
+            this.composeColor.green,
+            this.composeColor.blue,
+            this.composeColor.alpha,
+            this.composeColor.colorSpace.toInkColorSpaceId(),
+            size,
+            epsilon,
+        )
+
+    // Base implementation of copy() that all public versions call.
+    private fun copy(family: BrushFamily, color: ComposeColor, size: Float, epsilon: Float): Brush {
+        return if (
+            family == this.family &&
+                color == this.composeColor &&
+                size == this.size &&
+                epsilon == this.epsilon
+        ) {
+            // For a pure copy, return the same object, since it is immutable.
+            this
+        } else {
+            Brush(family, color, size, epsilon)
+        }
+    }
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged. To change the color, use [copyWithColorLong] or [copyWithColorIntArgb].
+     */
+    @JvmSynthetic
+    public fun copy(
+        family: BrushFamily = this.family,
+        size: Float = this.size,
+        epsilon: Float = this.epsilon,
+    ): Brush = copy(family, this.composeColor, size, epsilon)
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged. The color is specified as a [ColorLong], which can encode several different color
+     * spaces. sRGB and Display P3 are supported; a color in any other color space will be converted
+     * to Display P3.
+     *
+     * Some libraries (notably Jetpack UI Graphics) use [ULong] for [ColorLong]s, so the caller must
+     * call [ULong.toLong] on such a value before passing it to this method.
+     */
+    @JvmSynthetic
+    public fun copyWithColorLong(
+        family: BrushFamily = this.family,
+        @ColorLong colorLong: Long,
+        size: Float = this.size,
+        epsilon: Float = this.epsilon,
+    ): Brush = copy(family, ComposeColor(colorLong.toULong()), size, epsilon)
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged. The color is specified as a [ColorInt], which is in the sRGB color space by
+     * definition. Note that the [ColorInt] channel order puts alpha first (in the most significant
+     * byte).
+     *
+     * Kotlin interprets integer literals greater than `0x7fffffff` as [Long]s, so callers that want
+     * to specify a literal [ColorInt] with alpha >= 0x80 must call [Long.toInt] on the literal.
+     */
+    @JvmSynthetic
+    public fun copyWithColorIntArgb(
+        family: BrushFamily = this.family,
+        @ColorInt colorIntArgb: Int,
+        size: Float = this.size,
+        epsilon: Float = this.epsilon,
+    ): Brush = copy(family, ComposeColor(colorIntArgb), size, epsilon)
+
+    /**
+     * Returns a [Builder] with values set equivalent to `this`. Java developers, use the returned
+     * builder to build a copy of a Brush. Kotlin developers, see [copy] method.
+     */
+    public fun toBuilder(): Builder =
+        Builder().setFamily(family).setComposeColor(composeColor).setSize(size).setEpsilon(epsilon)
+
+    /**
+     * Builder for [Brush].
+     *
+     * Use Brush.Builder to construct a [Brush] with default values, overriding only as needed.
+     */
+    public class Builder {
+        private var family: BrushFamily? = null
+        private var composeColor: ComposeColor = DEFAULT_COMPOSE_COLOR
+
+        @FloatRange(
+            from = 0.0,
+            fromInclusive = false,
+            to = Double.POSITIVE_INFINITY,
+            toInclusive = false
+        )
+        private var size: Float? = null
+
+        @FloatRange(
+            from = 0.0,
+            fromInclusive = false,
+            to = Double.POSITIVE_INFINITY,
+            toInclusive = false
+        )
+        private var epsilon: Float? = null
+
+        /**
+         * Sets the [BrushFamily] for this brush. See [StockBrushes] for available [BrushFamily]
+         * values.
+         */
+        public fun setFamily(family: BrushFamily): Builder {
+            this.family = family
+            return this
+        }
+
+        internal fun setComposeColor(color: ComposeColor): Builder {
+            this.composeColor = color
+            return this
+        }
+
+        /**
+         * Sets the color using a [ColorLong], which can encode several different color spaces. sRGB
+         * and Display P3 are supported; a color in any other color space will be converted to
+         * Display P3.
+         *
+         * Some libraries (notably Jetpack UI Graphics) use [ULong] for [ColorLong]s, so the caller
+         * must call [ULong.toLong] on such a value before passing it to this method.
+         */
+        public fun setColorLong(@ColorLong colorLong: Long): Builder {
+            this.composeColor = ComposeColor(colorLong.toULong())
+            return this
+        }
+
+        /**
+         * Sets the color using a [ColorInt], which is in the sRGB color space by definition. Note
+         * that the [ColorInt] channel order puts alpha first (in the most significant byte).
+         *
+         * Kotlin interprets integer literals greater than `0x7fffffff` as [Long]s, so Kotlin
+         * callers that want to specify a literal [ColorInt] with alpha >= 0x80 must call
+         * [Long.toInt] on the literal.
+         */
+        public fun setColorIntArgb(@ColorInt colorInt: Int): Builder {
+            this.composeColor = ComposeColor(colorInt)
+            return this
+        }
+
+        public fun setSize(
+            @FloatRange(
+                from = 0.0,
+                fromInclusive = false,
+                to = Double.POSITIVE_INFINITY,
+                toInclusive = false
+            )
+            size: Float
+        ): Builder {
+            this.size = size
+            return this
+        }
+
+        public fun setEpsilon(
+            @FloatRange(
+                from = 0.0,
+                fromInclusive = false,
+                to = Double.POSITIVE_INFINITY,
+                toInclusive = false
+            )
+            epsilon: Float
+        ): Builder {
+            this.epsilon = epsilon
+            return this
+        }
+
+        public fun build(): Brush =
+            Brush(
+                family =
+                    checkNotNull(family) {
+                        "brush family must be specified before calling build()"
+                    },
+                composeColor = composeColor,
+                size = checkNotNull(size) { "brush size must be specified before calling build()" },
+                epsilon =
+                    checkNotNull(epsilon) {
+                        "brush epsilon must be specified before calling build()"
+                    },
+            )
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Brush) return false
+
+        if (family != other.family) return false
+        if (composeColor != other.composeColor) return false
+        if (size != other.size) return false
+        if (epsilon != other.epsilon) return false
+
+        return true
+    }
+
+    // NOMUTANTS -- not testing exact hashCode values, just that equality implies the same hashCode.
+    override fun hashCode(): Int {
+        var result = family.hashCode()
+        result = 31 * result + composeColor.hashCode()
+        result = 31 * result + size.hashCode()
+        result = 31 * result + epsilon.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "Brush(family=$family, color=$composeColor, size=$size, epsilon=$epsilon)"
+    }
+
+    /** Delete native Brush memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrush(nativePointer)
+    }
+
+    /** Create underlying native object and return reference for all subsequent native calls. */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrush(
+        familyNativePointer: Long,
+        colorRed: Float,
+        colorGreen: Float,
+        colorBlue: Float,
+        colorAlpha: Float,
+        colorSpace: Int,
+        size: Float,
+        epsilon: Float,
+    ): Long
+
+    /** Release the underlying memory allocated in [nativeCreateBrush]. */
+    private external fun nativeFreeBrush(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+
+        private val DEFAULT_COMPOSE_COLOR = ComposeColor.Black
+
+        /**
+         * Returns a new [Brush] with the color specified by a [ColorLong], which can encode several
+         * different color spaces. sRGB and Display P3 are supported; a color in any other color
+         * space will be converted to Display P3.
+         *
+         * Some libraries (notably Jetpack UI Graphics) use [ULong] for [ColorLong]s, so the caller
+         * must call [ULong.toLong] on such a value before passing it to this method.
+         */
+        @JvmStatic
+        public fun withColorLong(
+            family: BrushFamily,
+            @ColorLong colorLong: Long,
+            size: Float,
+            epsilon: Float,
+        ): Brush = Brush(family, ComposeColor(colorLong.toULong()), size, epsilon)
+
+        /**
+         * Returns a new [Brush] with the color specified by a [ColorInt], which is in the sRGB
+         * color space by definition. Note that the [ColorInt] channel order puts alpha first (in
+         * the most significant byte).
+         *
+         * Kotlin interprets integer literals greater than `0x7fffffff` as [Long]s, so callers that
+         * want to specify a literal [ColorInt] with alpha >= 0x80 must call [Long.toInt] on the
+         * literal.
+         */
+        @JvmStatic
+        public fun withColorIntArgb(
+            family: BrushFamily,
+            @ColorInt colorIntArgb: Int,
+            size: Float,
+            epsilon: Float,
+        ): Brush = Brush(family, ComposeColor(colorIntArgb), size, epsilon)
+
+        /** Returns a new [Brush.Builder]. */
+        @JvmStatic public fun builder(): Builder = Builder()
+    }
 }
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushBehavior.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushBehavior.kt
new file mode 100644
index 0000000..5fd4b1c
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushBehavior.kt
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import androidx.ink.nativeloader.NativeLoader
+import java.util.Collections.unmodifiableSet
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmStatic
+
+/**
+ * Specification for a behavior that maps values of an input property to multipliers/offsets to the
+ * value of a tip property through a configurable curve.
+ *
+ * Tip properties consist of the shape and a color-shift that can be used to augment the [Brush]
+ * color.
+ *
+ * The effect of each behavior is calculated as follows:
+ * 1. If the current input tool type is not enabled in [enabledToolTypes], or the [source] input
+ *    property is not reported, then the behavior is inactive and skipped.
+ * 2. The [source] enumerator is used to retrieve the appropriate value from the current input
+ *    state.
+ * 3. The input value is mapped to a unitless value in the range [0, 1] by inverse linear
+ *    interpolation using the range [sourceValueRangeLowerBound, sourceValueRangeUpperBound] and
+ *    [sourceOutOfRangeBehavior].
+ * 4. The result of the previous step is mapped to a new unitless value according to the
+ *    [responseCurve] easing function.
+ * 5. The unitless output value from the previous step is linearly interpolated or extrapolated
+ *    using the range [targetModifierRangeLowerBound, targetModifierRangeUpperBound] to produce a
+ *    proposed modifier (either an offset or a multiplier, depending on the [Target]) to be applied
+ *    to the [target] tip property.
+ * 6. The behavior's actual modifier value decays towards this proposed modifier over time based on
+ *    [responseTimeMillis] (or snaps to it instantly if [responseTimeMillis] is zero).
+ *
+ * Note that the elements of sourceValueRange and targetModifierRange do not have a required order.
+ * For example, [sourceValueRangeLowerBound] can be greater than or less than
+ * [sourceValueRangeUpperBound]. In either case, [sourceValueRangeLowerBound] will correspond to
+ * passing 0 as an input to the [responseCurve].
+ *
+ * For each input in a stroke, [BrushTip.behaviors] are applied as follows:
+ * 1. The actual target modifier (as calculated above) for each tip property is accumulated from
+ *    every [BrushBehavior] present on the current [BrushTip]. Multiple behaviors can affect the
+ *    same [Target]. Depending on the [Target], modifiers from multiple behaviors will stack either
+ *    additively or multiplicatively, according to the documentation for that [Target]. Regardless,
+ *    the order of specified behaviors does not affect the result.
+ * 2. The modifiers are applied to the shape and color shift values of the tip's state according to
+ *    the documentation for each [Target]. The resulting tip property values are then clamped or
+ *    normalized to within their valid range of values. E.g. the final value of
+ *    [BrushTip.cornerRounding] will be clamped within [0, 1]. Generally: The affected shape values
+ *    are those found in [BrushTip] members. The color shift values remain in the range -100% to
+ *    +100%. Note that when stored on a vertex, the color shift is encoded such that each channel is
+ *    in the range [0, 1], where 0.5 represents a 0% shift.
+ *
+ * Note that the accumulated tip shape property offsets may be modified by the implementation before
+ * being applied: The rates of change of shape properties may be constrained to keep them from
+ * changing too rapidly with respect to distance traveled from one input to the next.
+ *
+ * Note to Java developers: use [BrushBehavior.Builder] for building a BrushBehavior with default
+ * values.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@ExperimentalInkCustomBrushApi
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+public class BrushBehavior(
+    public val source: Source,
+    public val target: Target,
+    public val sourceValueRangeLowerBound: Float,
+    public val sourceValueRangeUpperBound: Float,
+    public val targetModifierRangeLowerBound: Float,
+    public val targetModifierRangeUpperBound: Float,
+    public val sourceOutOfRangeBehavior: OutOfRange = OutOfRange.CLAMP,
+    public val responseCurve: EasingFunction = EasingFunction.Predefined.LINEAR,
+    public val responseTimeMillis: Long = 0L,
+    // The [enabledToolTypes] val below is a defensive copy of this parameter.
+    enabledToolTypes: Set = ALL_TOOL_TYPES,
+    public val isFallbackFor: OptionalInputProperty? = null,
+) {
+    public val enabledToolTypes: Set = unmodifiableSet(enabledToolTypes.toSet())
+
+    /** A handle to the underlying native [BrushBehavior] object. */
+    internal val nativePointer: Long = createNativeBrushBehavior()
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @JvmSynthetic
+    public fun copy(
+        source: Source = this.source,
+        target: Target = this.target,
+        sourceOutOfRangeBehavior: OutOfRange = this.sourceOutOfRangeBehavior,
+        sourceValueRangeLowerBound: Float = this.sourceValueRangeLowerBound,
+        sourceValueRangeUpperBound: Float = this.sourceValueRangeUpperBound,
+        targetModifierRangeLowerBound: Float = this.targetModifierRangeLowerBound,
+        targetModifierRangeUpperBound: Float = this.targetModifierRangeUpperBound,
+        responseCurve: EasingFunction = this.responseCurve,
+        responseTimeMillis: Long = this.responseTimeMillis,
+        enabledToolTypes: Set = this.enabledToolTypes,
+        isFallbackFor: OptionalInputProperty? = this.isFallbackFor,
+    ): BrushBehavior =
+        BrushBehavior(
+            source,
+            target,
+            sourceValueRangeLowerBound,
+            sourceValueRangeUpperBound,
+            targetModifierRangeLowerBound,
+            targetModifierRangeUpperBound,
+            sourceOutOfRangeBehavior,
+            responseCurve,
+            responseTimeMillis,
+            enabledToolTypes,
+            isFallbackFor,
+        )
+
+    /**
+     * Returns a [Builder] with values set equivalent to `this`. Java developers, use the returned
+     * builder to build a copy of a BrushBehavior.
+     */
+    public fun toBuilder(): Builder =
+        Builder()
+            .setSource(source)
+            .setTarget(target)
+            .setSourceOutOfRangeBehavior(sourceOutOfRangeBehavior)
+            .setSourceValueRangeLowerBound(sourceValueRangeLowerBound)
+            .setSourceValueRangeUpperBound(sourceValueRangeUpperBound)
+            .setTargetModifierRangeLowerBound(targetModifierRangeLowerBound)
+            .setTargetModifierRangeUpperBound(targetModifierRangeUpperBound)
+            .setResponseCurve(responseCurve)
+            .setResponseTimeMillis(responseTimeMillis)
+            .setEnabledToolTypes(enabledToolTypes)
+            .setIsFallbackFor(isFallbackFor)
+
+    /**
+     * Builder for [BrushBehavior].
+     *
+     * For Java developers, use BrushBehavior.Builder to construct a [BrushBehavior] with default
+     * values, overriding only as needed. For example:
+     * ```
+     * BrushBehavior behavior = new BrushBehavior.Builder()
+     *   .setSource(...)
+     *   .setTarget(...)
+     *   .setSourceOutOfRangeBehavior(...)
+     *   .setSourceValueRangeLowerBound(...)
+     *   .build();
+     * ```
+     */
+    @Suppress("ScopeReceiverThis")
+    public class Builder {
+        private var source: Source = Source.NORMALIZED_PRESSURE
+        private var target: Target = Target.SIZE_MULTIPLIER
+        private var sourceOutOfRangeBehavior: OutOfRange = OutOfRange.CLAMP
+        private var sourceValueRangeLowerBound: Float = 0f
+        private var sourceValueRangeUpperBound: Float = 1f
+        private var targetModifierRangeLowerBound: Float = 0f
+        private var targetModifierRangeUpperBound: Float = 1f
+        private var responseCurve: EasingFunction = EasingFunction.Predefined.LINEAR
+        private var responseTimeMillis: Long = 0L
+        private var enabledToolTypes: Set = ALL_TOOL_TYPES
+        private var isFallbackFor: OptionalInputProperty? = null
+
+        public fun setSource(source: Source): Builder = apply { this.source = source }
+
+        public fun setTarget(target: Target): Builder = apply { this.target = target }
+
+        public fun setSourceOutOfRangeBehavior(sourceOutOfRangeBehavior: OutOfRange): Builder =
+            apply {
+                this.sourceOutOfRangeBehavior = sourceOutOfRangeBehavior
+            }
+
+        public fun setSourceValueRangeLowerBound(sourceValueRangeLowerBound: Float): Builder =
+            apply {
+                this.sourceValueRangeLowerBound = sourceValueRangeLowerBound
+            }
+
+        public fun setSourceValueRangeUpperBound(sourceValueRangeUpperBound: Float): Builder =
+            apply {
+                this.sourceValueRangeUpperBound = sourceValueRangeUpperBound
+            }
+
+        public fun setTargetModifierRangeLowerBound(targetModifierRangeLowerBound: Float): Builder =
+            apply {
+                this.targetModifierRangeLowerBound = targetModifierRangeLowerBound
+            }
+
+        public fun setTargetModifierRangeUpperBound(targetModifierRangeUpperBound: Float): Builder =
+            apply {
+                this.targetModifierRangeUpperBound = targetModifierRangeUpperBound
+            }
+
+        public fun setResponseCurve(responseCurve: EasingFunction): Builder = apply {
+            this.responseCurve = responseCurve
+        }
+
+        public fun setResponseTimeMillis(responseTimeMillis: Long): Builder = apply {
+            this.responseTimeMillis = responseTimeMillis
+        }
+
+        public fun setEnabledToolTypes(enabledToolTypes: Set): Builder = apply {
+            this.enabledToolTypes = enabledToolTypes.toSet()
+        }
+
+        public fun setIsFallbackFor(isFallbackFor: OptionalInputProperty?): Builder = apply {
+            this.isFallbackFor = isFallbackFor
+        }
+
+        public fun build(): BrushBehavior =
+            BrushBehavior(
+                source,
+                target,
+                sourceValueRangeLowerBound,
+                sourceValueRangeUpperBound,
+                targetModifierRangeLowerBound,
+                targetModifierRangeUpperBound,
+                sourceOutOfRangeBehavior,
+                responseCurve,
+                responseTimeMillis,
+                enabledToolTypes,
+                isFallbackFor,
+            )
+    }
+
+    override fun equals(other: Any?): Boolean {
+        // NOMUTANTS -- Check the instance first to short circuit faster.
+        if (other === this) return true
+        if (other == null || other !is BrushBehavior) return false
+        return (source == other.source &&
+            target == other.target &&
+            sourceOutOfRangeBehavior == other.sourceOutOfRangeBehavior &&
+            sourceValueRangeLowerBound == other.sourceValueRangeLowerBound &&
+            sourceValueRangeUpperBound == other.sourceValueRangeUpperBound &&
+            targetModifierRangeLowerBound == other.targetModifierRangeLowerBound &&
+            targetModifierRangeUpperBound == other.targetModifierRangeUpperBound &&
+            responseCurve == other.responseCurve &&
+            responseTimeMillis == other.responseTimeMillis &&
+            enabledToolTypes == other.enabledToolTypes &&
+            isFallbackFor == other.isFallbackFor)
+    }
+
+    override fun hashCode(): Int {
+        var result = source.hashCode()
+        result = 31 * result + target.hashCode()
+        result = 31 * result + sourceOutOfRangeBehavior.hashCode()
+        result = 31 * result + sourceValueRangeLowerBound.hashCode()
+        result = 31 * result + sourceValueRangeUpperBound.hashCode()
+        result = 31 * result + targetModifierRangeLowerBound.hashCode()
+        result = 31 * result + targetModifierRangeUpperBound.hashCode()
+        result = 31 * result + responseCurve.hashCode()
+        result = 31 * result + responseTimeMillis.hashCode()
+        result = 31 * result + (isFallbackFor?.hashCode() ?: 0)
+        result = 31 * result + enabledToolTypes.hashCode()
+        return result
+    }
+
+    override fun toString(): String =
+        "BrushBehavior(source=$source, target=$target, " +
+            "sourceOutOfRangeBehavior=$sourceOutOfRangeBehavior, " +
+            "sourceValueRangeLowerBound=$sourceValueRangeLowerBound, " +
+            "sourceValueRangeUpperBound=$sourceValueRangeUpperBound, " +
+            "targetModifierRangeLowerBound=$targetModifierRangeLowerBound, " +
+            "targetModifierRangeUpperBound=$targetModifierRangeUpperBound, " +
+            "responseCurve=$responseCurve, responseTimeMillis=$responseTimeMillis, " +
+            "enabledToolTypes=$enabledToolTypes, isFallbackFor=$isFallbackFor)"
+
+    /** Delete native BrushBehavior memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrushBehavior(nativePointer)
+    }
+
+    /**
+     * Depending on the variant of the responseCurve, call the corresponding native method that
+     * accepts the EasingFunction arguments to create it.
+     */
+    private fun createNativeBrushBehavior(): Long =
+        when (responseCurve) {
+            is EasingFunction.Predefined ->
+                nativeCreateBrushBehaviorPredefined(
+                    source.value,
+                    target.value,
+                    sourceOutOfRangeBehavior.value,
+                    sourceValueRangeLowerBound,
+                    sourceValueRangeUpperBound,
+                    targetModifierRangeLowerBound,
+                    targetModifierRangeUpperBound,
+                    responseCurve.value,
+                    responseTimeMillis,
+                    enabledToolTypes.contains(InputToolType.MOUSE),
+                    enabledToolTypes.contains(InputToolType.TOUCH),
+                    enabledToolTypes.contains(InputToolType.STYLUS),
+                    enabledToolTypes.contains(InputToolType.UNKNOWN),
+                    isFallbackFor?.value ?: -1,
+                )
+            is EasingFunction.Steps ->
+                nativeCreateBrushBehaviorSteps(
+                    source.value,
+                    target.value,
+                    sourceOutOfRangeBehavior.value,
+                    sourceValueRangeLowerBound,
+                    sourceValueRangeUpperBound,
+                    targetModifierRangeLowerBound,
+                    targetModifierRangeUpperBound,
+                    responseCurve.stepCount,
+                    responseCurve.stepPosition.value,
+                    responseTimeMillis,
+                    enabledToolTypes.contains(InputToolType.MOUSE),
+                    enabledToolTypes.contains(InputToolType.TOUCH),
+                    enabledToolTypes.contains(InputToolType.STYLUS),
+                    enabledToolTypes.contains(InputToolType.UNKNOWN),
+                    isFallbackFor?.value ?: -1,
+                )
+            is EasingFunction.CubicBezier ->
+                nativeCreateBrushBehaviorCubicBezier(
+                    source.value,
+                    target.value,
+                    sourceOutOfRangeBehavior.value,
+                    sourceValueRangeLowerBound,
+                    sourceValueRangeUpperBound,
+                    targetModifierRangeLowerBound,
+                    targetModifierRangeUpperBound,
+                    responseCurve.x1,
+                    responseCurve.y1,
+                    responseCurve.x2,
+                    responseCurve.y2,
+                    responseTimeMillis,
+                    enabledToolTypes.contains(InputToolType.MOUSE),
+                    enabledToolTypes.contains(InputToolType.TOUCH),
+                    enabledToolTypes.contains(InputToolType.STYLUS),
+                    enabledToolTypes.contains(InputToolType.UNKNOWN),
+                    isFallbackFor?.value ?: -1,
+                )
+            is EasingFunction.Linear ->
+                nativeCreateBrushBehaviorLinear(
+                    source.value,
+                    target.value,
+                    sourceOutOfRangeBehavior.value,
+                    sourceValueRangeLowerBound,
+                    sourceValueRangeUpperBound,
+                    targetModifierRangeLowerBound,
+                    targetModifierRangeUpperBound,
+                    FloatArray(responseCurve.points.size * 2).apply {
+                        var index = 0
+                        for (point in responseCurve.points) {
+                            set(index, point.x)
+                            ++index
+                            set(index, point.y)
+                            ++index
+                        }
+                    },
+                    responseTimeMillis,
+                    enabledToolTypes.contains(InputToolType.MOUSE),
+                    enabledToolTypes.contains(InputToolType.TOUCH),
+                    enabledToolTypes.contains(InputToolType.STYLUS),
+                    enabledToolTypes.contains(InputToolType.UNKNOWN),
+                    isFallbackFor?.value ?: -1,
+                )
+            else -> throw IllegalArgumentException("Unsupported response curve: $responseCurve")
+        }
+
+    /**
+     * Create underlying native brush behavior with response curve of type
+     * [EasingFunction.Predefined] and return its memory address.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushBehaviorPredefined(
+        source: Int,
+        target: Int,
+        sourceOutOfRangeBehavior: Int,
+        sourceValueRangeLowerBound: Float,
+        sourceValueRangeUpperBound: Float,
+        targetModifierRangeLowerBound: Float,
+        targetModifierRangeUpperBound: Float,
+        predefinedResponseCurve: Int,
+        responseTimeMillis: Long,
+        mouseEnabled: Boolean,
+        touchEnabled: Boolean,
+        stylusEnabled: Boolean,
+        unknownEnabled: Boolean,
+        isFallbackFor: Int,
+    ): Long
+
+    /**
+     * Create underlying native brush behavior with response curve of type [EasingFunction.Steps]
+     * and return its memory address.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushBehaviorSteps(
+        source: Int,
+        target: Int,
+        sourceOutOfRangeBehavior: Int,
+        sourceValueRangeLowerBound: Float,
+        sourceValueRangeUpperBound: Float,
+        targetModifierRangeLowerBound: Float,
+        targetModifierRangeUpperBound: Float,
+        stepsCount: Int,
+        stepsPosition: Int,
+        responseTimeMillis: Long,
+        mouseEnabled: Boolean,
+        touchEnabled: Boolean,
+        stylusEnabled: Boolean,
+        unknownEnabled: Boolean,
+        isFallbackFor: Int,
+    ): Long
+
+    /**
+     * Create underlying native brush behavior with response curve of type
+     * [EasingFunction.CubicBezier] and return its memory address.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushBehaviorCubicBezier(
+        source: Int,
+        target: Int,
+        sourceOutOfRangeBehavior: Int,
+        sourceValueRangeLowerBound: Float,
+        sourceValueRangeUpperBound: Float,
+        targetModifierRangeLowerBound: Float,
+        targetModifierRangeUpperBound: Float,
+        cubicBezierX1: Float,
+        cubicBezierX2: Float,
+        cubicBezierY1: Float,
+        cubicBezierY2: Float,
+        responseTimeMillis: Long,
+        mouseEnabled: Boolean,
+        touchEnabled: Boolean,
+        stylusEnabled: Boolean,
+        unknownEnabled: Boolean,
+        isFallbackFor: Int,
+    ): Long
+
+    /**
+     * Create underlying native brush behavior with response curve of type [EasingFunction.Linear]
+     * and return its memory address.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushBehaviorLinear(
+        source: Int,
+        target: Int,
+        sourceOutOfRangeBehavior: Int,
+        sourceValueRangeLowerBound: Float,
+        sourceValueRangeUpperBound: Float,
+        targetModifierRangeLowerBound: Float,
+        targetModifierRangeUpperBound: Float,
+        points: FloatArray,
+        responseTimeMillis: Long,
+        mouseEnabled: Boolean,
+        touchEnabled: Boolean,
+        stylusEnabled: Boolean,
+        unknownEnabled: Boolean,
+        isFallbackFor: Int,
+    ): Long
+
+    /**
+     * Release the underlying memory allocated in [nativeCreateBrushBehaviorLinear],
+     * [nativeCreateBrushBehaviorPredefined], [nativeCreateBrushBehaviorSteps], or
+     * [nativeCreateBrushBehaviorCubicBezier].
+     */
+    private external fun nativeFreeBrushBehavior(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+
+        /** Returns a new [BrushBehavior.Builder]. */
+        @JvmStatic public fun builder(): Builder = Builder()
+
+        @JvmField
+        public val ALL_TOOL_TYPES: Set =
+            setOf(
+                InputToolType.STYLUS,
+                InputToolType.UNKNOWN,
+                InputToolType.MOUSE,
+                InputToolType.TOUCH
+            )
+    }
+
+    /**
+     * List of input properties along with their units that can act as sources for a
+     * [BrushBehavior].
+     */
+    public class Source private constructor(@JvmField internal val value: Int) {
+        public fun toSimpleString(): String =
+            when (this) {
+                CONSTANT_ZERO -> "CONSTANT_ZERO"
+                NORMALIZED_PRESSURE -> "NORMALIZED_PRESSURE"
+                TILT_IN_RADIANS -> "TILT_IN_RADIANS"
+                TILT_X_IN_RADIANS -> "TILT_X_IN_RADIANS"
+                TILT_Y_IN_RADIANS -> "TILT_Y_IN_RADIANS"
+                ORIENTATION_IN_RADIANS -> "ORIENTATION_IN_RADIANS"
+                ORIENTATION_ABOUT_ZERO_IN_RADIANS -> "ORIENTATION_ABOUT_ZERO_IN_RADIANS"
+                SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND ->
+                    "SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND"
+                VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND ->
+                    "VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND"
+                VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND ->
+                    "VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND"
+                DIRECTION_IN_RADIANS -> "DIRECTION_IN_RADIANS"
+                DIRECTION_ABOUT_ZERO_IN_RADIANS -> "DIRECTION_ABOUT_ZERO_IN_RADIANS"
+                NORMALIZED_DIRECTION_X -> "NORMALIZED_DIRECTION_X"
+                NORMALIZED_DIRECTION_Y -> "NORMALIZED_DIRECTION_Y"
+                DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE"
+                TIME_OF_INPUT_IN_SECONDS -> "TIME_OF_INPUT_IN_SECONDS"
+                TIME_OF_INPUT_IN_MILLIS -> "TIME_OF_INPUT_IN_MILLIS"
+                PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE"
+                PREDICTED_TIME_ELAPSED_IN_SECONDS -> "PREDICTED_TIME_ELAPSED_IN_SECONDS"
+                PREDICTED_TIME_ELAPSED_IN_MILLIS -> "PREDICTED_TIME_ELAPSED_IN_MILLIS"
+                DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE"
+                TIME_SINCE_INPUT_IN_SECONDS -> "TIME_SINCE_INPUT_IN_SECONDS"
+                TIME_SINCE_INPUT_IN_MILLIS -> "TIME_SINCE_INPUT_IN_MILLIS"
+                ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED ->
+                    "ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+                ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED ->
+                    "ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+                ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED ->
+                    "ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+                ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED ->
+                    "ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+                ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED ->
+                    "ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+                INPUT_SPEED_IN_CENTIMETERS_PER_SECOND -> "INPUT_SPEED_IN_CENTIMETERS_PER_SECOND"
+                INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND ->
+                    "INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND"
+                INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND ->
+                    "INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND"
+                INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS -> "INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS"
+                PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS ->
+                    "PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS"
+                INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED ->
+                    "INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED"
+                INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED ->
+                    "INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED"
+                INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED ->
+                    "INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED"
+                INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED ->
+                    "INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED"
+                INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED ->
+                    "INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + this.toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is Source) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+
+            /**
+             * A source whose value is always zero. This can be used to provide a constant modifier
+             * to a target value. Normally this is not needed, because you can just set those
+             * modifiers directly on the [BrushTip], but it can become useful when combined with the
+             * [enabledToolTypes] and/or [isFallbackFor] fields to only conditionally enable it.
+             */
+            @JvmField public val CONSTANT_ZERO: Source = Source(0)
+            /** Stylus or touch pressure with values reported in the range [0, 1]. */
+            @JvmField public val NORMALIZED_PRESSURE: Source = Source(1)
+            /** Stylus tilt with values reported in the range [0, π/2] radians. */
+            @JvmField public val TILT_IN_RADIANS: Source = Source(2)
+            /**
+             * Stylus tilt along the x axis in the range [-π/2, π/2], with a positive value
+             * corresponding to tilt toward the respective positive axis. In order for those values
+             * to be reported, both tilt and orientation have to be populated on the StrokeInput.
+             */
+            @JvmField public val TILT_X_IN_RADIANS: Source = Source(3)
+            /**
+             * Stylus tilt along the y axis in the range [-π/2, π/2], with a positive value
+             * corresponding to tilt toward the respective positive axis. In order for those values
+             * to be reported, both tilt and orientation have to be populated on the StrokeInput.
+             */
+            @JvmField public val TILT_Y_IN_RADIANS: Source = Source(4)
+            /** Stylus orientation with values reported in the range [0, 2π). */
+            @JvmField public val ORIENTATION_IN_RADIANS: Source = Source(5)
+            /** Stylus orientation with values reported in the range (-π, π]. */
+            @JvmField public val ORIENTATION_ABOUT_ZERO_IN_RADIANS: Source = Source(6)
+            /**
+             * Pointer speed with values >= 0 in distance units per second, where one distance unit
+             * is equal to the brush size.
+             */
+            @JvmField public val SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND: Source = Source(7)
+            /**
+             * Signed x component of pointer velocity in distance units per second, where one
+             * distance unit is equal to the brush size.
+             */
+            @JvmField
+            public val VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND: Source = Source(8)
+            /**
+             * Signed y component of pointer velocity in distance units per second, where one
+             * distance unit is equal to the brush size.
+             */
+            @JvmField
+            public val VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND: Source = Source(9)
+            /**
+             * The angle of the stroke's current direction of travel in stroke space, normalized to
+             * the range [0, 2π). A value of 0 indicates the direction of the positive X-axis in
+             * stroke space; a value of π/2 indicates the direction of the positive Y-axis in stroke
+             * space.
+             */
+            @JvmField public val DIRECTION_IN_RADIANS: Source = Source(10)
+            /**
+             * The angle of the stroke's current direction of travel in stroke space, normalized to
+             * the range (-π, π]. A value of 0 indicates the direction of the positive X-axis in
+             * stroke space; a value of π/2 indicates the direction of the positive Y-axis in stroke
+             * space.
+             */
+            @JvmField public val DIRECTION_ABOUT_ZERO_IN_RADIANS: Source = Source(11)
+            /**
+             * Signed x component of the normalized travel direction, with values in the range
+             * [-1, 1].
+             */
+            @JvmField public val NORMALIZED_DIRECTION_X: Source = Source(12)
+            /**
+             * Signed y component of the normalized travel direction, with values in the range
+             * [-1, 1].
+             */
+            @JvmField public val NORMALIZED_DIRECTION_Y: Source = Source(13)
+            /**
+             * Distance traveled by the inputs of the current stroke, starting at 0 at the first
+             * input, where one distance unit is equal to the brush size.
+             */
+            @JvmField public val DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE: Source = Source(14)
+            /**
+             * The time elapsed, in seconds, from when the stroke started to when this part of the
+             * stroke was drawn. The value remains fixed for any given part of the stroke once
+             * drawn.
+             */
+            @JvmField public val TIME_OF_INPUT_IN_SECONDS: Source = Source(15)
+            /**
+             * The time elapsed, in millis, from when the stroke started to when this part of the
+             * stroke was drawn. The value remains fixed for any given part of the stroke once
+             * drawn.
+             */
+            @JvmField public val TIME_OF_INPUT_IN_MILLIS: Source = Source(16)
+            /**
+             * Distance traveled by the inputs of the current prediction, starting at 0 at the last
+             * non-predicted input, where one distance unit is equal to the brush size. For cases
+             * where prediction hasn't started yet, we don't return a negative value, but clamp to a
+             * min of 0.
+             */
+            @JvmField
+            public val PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE: Source = Source(17)
+            /**
+             * Elapsed time of the prediction, starting at 0 at the last non-predicted input. For
+             * cases where prediction hasn't started yet, we don't return a negative value, but
+             * clamp to a min of 0.
+             */
+            @JvmField public val PREDICTED_TIME_ELAPSED_IN_SECONDS: Source = Source(18)
+            /**
+             * Elapsed time of the prediction, starting at 0 at the last non-predicted input. For
+             * cases where prediction hasn't started yet, we don't return a negative value, but
+             * clamp to a min of 0.
+             */
+            @JvmField public val PREDICTED_TIME_ELAPSED_IN_MILLIS: Source = Source(19)
+            /**
+             * The distance left to be traveled from a given input to the current last input of the
+             * stroke, where one distance unit is equal to the brush size. This value changes for
+             * each input as the stroke is drawn.
+             */
+            @JvmField public val DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE: Source = Source(20)
+            /**
+             * The amount of time that has elapsed, in seconds, since this part of the stroke was
+             * drawn. This continues to increase even after all stroke inputs have completed, and
+             * can be used to drive stroke animations. This enumerators are only compatible with a
+             * [sourceOutOfRangeBehavior] of [OutOfRange.CLAMP], to ensure that the animation will
+             * eventually end.
+             */
+            @JvmField public val TIME_SINCE_INPUT_IN_SECONDS: Source = Source(21)
+            /**
+             * The amount of time that has elapsed, in millis, since this part of the stroke was
+             * drawn. This continues to increase even after all stroke inputs have completed, and
+             * can be used to drive stroke animations. This enumerators are only compatible with a
+             * [sourceOutOfRangeBehavior] of [OutOfRange.CLAMP], to ensure that the animation will
+             * eventually end.
+             */
+            @JvmField public val TIME_SINCE_INPUT_IN_MILLIS: Source = Source(22)
+            /**
+             * Directionless pointer acceleration with values >= 0 in distance units per second
+             * squared, where one distance unit is equal to the brush size.
+             */
+            @JvmField
+            public val ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED: Source =
+                Source(23)
+            /**
+             * Signed x component of pointer acceleration in distance units per second squared,
+             * where one distance unit is equal to the brush size.
+             */
+            @JvmField
+            public val ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED: Source =
+                Source(24)
+            /**
+             * Signed y component of pointer acceleration in distance units per second squared,
+             * where one distance unit is equal to the brush size.
+             */
+            @JvmField
+            public val ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED: Source =
+                Source(25)
+            /**
+             * Pointer acceleration along the current direction of travel in distance units per
+             * second squared, where one distance unit is equal to the brush size. A positive value
+             * indicates that the pointer is accelerating along the current direction of travel,
+             * while a negative value indicates that the pointer is decelerating.
+             */
+            @JvmField
+            public val ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED: Source =
+                Source(26)
+            /**
+             * Pointer acceleration perpendicular to the current direction of travel in distance
+             * units per second squared, where one distance unit is equal to the brush size. If the
+             * X- and Y-axes of stroke space were rotated so that the positive X-axis points in the
+             * direction of stroke travel, then a positive value for this source indicates
+             * acceleration along the positive Y-axis (and a negative value indicates acceleration
+             * along the negative Y-axis).
+             */
+            @JvmField
+            public val ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED: Source =
+                Source(27)
+            /**
+             * The physical speed of the input pointer at the point in question, in centimeters per
+             * second.
+             */
+            @JvmField public val INPUT_SPEED_IN_CENTIMETERS_PER_SECOND: Source = Source(28)
+            /**
+             * Signed x component of the physical velocity of the input pointer at the point in
+             * question, in centimeters per second.
+             */
+            @JvmField public val INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND: Source = Source(29)
+            /**
+             * Signed y component of the physical velocity of the input pointer at the point in
+             * question, in centimeters per second.
+             */
+            @JvmField public val INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND: Source = Source(30)
+            /**
+             * The physical distance traveled by the input pointer from the start of the stroke
+             * along the input path to the point in question, in centimeters.
+             */
+            @JvmField public val INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS: Source = Source(31)
+            /**
+             * The physical distance that the input pointer would have to travel from its actual
+             * last real position along its predicted path to reach the predicted point in question,
+             * in centimeters. For points on the stroke before the predicted portion, this has a
+             * value of zero.
+             */
+            @JvmField
+            public val PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS: Source = Source(32)
+            /**
+             * The directionless physical acceleration of the input pointer at the point in
+             * question, with values >= 0, in centimeters per second squared.
+             */
+            @JvmField
+            public val INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED: Source = Source(33)
+            /**
+             * Signed x component of the physical acceleration of the input pointer, in centimeters
+             * per second squared.
+             */
+            @JvmField
+            public val INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED: Source = Source(34)
+            /**
+             * Signed y component of the physical acceleration of the input pointer, in centimeters
+             * per second squared.
+             */
+            @JvmField
+            public val INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED: Source = Source(35)
+            /**
+             * The physical acceleration of the input pointer along its current direction of travel
+             * at the point in question, in centimeters per second squared. A positive value
+             * indicates that the pointer is accelerating along the current direction of travel,
+             * while a negative value indicates that the pointer is decelerating.
+             */
+            @JvmField
+            public val INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED: Source =
+                Source(36)
+            /**
+             * The physical acceleration of the input pointer perpendicular to its current direction
+             * of travel at the point in question, in centimeters per second squared. If the X- and
+             * Y-axes of stroke space were rotated so that the positive X-axis points in the
+             * direction of stroke travel, then a positive value for this source indicates
+             * acceleration along the positive Y-axis (and a negative value indicates acceleration
+             * along the negative Y-axis).
+             */
+            @JvmField
+            public val INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED: Source =
+                Source(37)
+            private const val PREFIX = "BrushBehavior.Source."
+        }
+    }
+
+    /** List of tip properties that can be modified by a [BrushBehavior]. */
+    public class Target private constructor(@JvmField internal val value: Int) {
+
+        public fun toSimpleString(): String =
+            when (this) {
+                WIDTH_MULTIPLIER -> "WIDTH_MULTIPLIER"
+                HEIGHT_MULTIPLIER -> "HEIGHT_MULTIPLIER"
+                SIZE_MULTIPLIER -> "SIZE_MULTIPLIER"
+                SLANT_OFFSET_IN_RADIANS -> "SLANT_OFFSET_IN_RADIANS"
+                PINCH_OFFSET -> "PINCH_OFFSET"
+                ROTATION_OFFSET_IN_RADIANS -> "ROTATION_OFFSET_IN_RADIANS"
+                CORNER_ROUNDING_OFFSET -> "CORNER_ROUNDING_OFFSET"
+                POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE"
+                POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE"
+                POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE"
+                POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE ->
+                    "POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE"
+                HUE_OFFSET_IN_RADIANS -> "HUE_OFFSET_IN_RADIANS"
+                SATURATION_MULTIPLIER -> "SATURATION_MULTIPLIER"
+                LUMINOSITY -> "LUMINOSITY"
+                OPACITY_MULTIPLIER -> "OPACITY_MULTIPLIER"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + this.toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is Target) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+
+            /**
+             * Scales the brush-tip width, starting from the value calculated using
+             * [BrushTip.scaleX] and [BrushTip.scaleY]. The final brush width is clamped to a
+             * maximum of twice the base width. If multiple behaviors have one of these targets,
+             * they stack multiplicatively.
+             */
+            @JvmField public val WIDTH_MULTIPLIER: Target = Target(0)
+            /**
+             * Scales the brush-tip height, starting from the value calculated using
+             * [BrushTip.scaleX] and [BrushTip.scaleY]. The final brush height is clamped to a
+             * maximum of twice the base height. If multiple behaviors have one of these targets,
+             * they stack multiplicatively.
+             */
+            @JvmField public val HEIGHT_MULTIPLIER: Target = Target(1)
+            /** Convenience enumerator to target both [WIDTH_MULTIPLIER] and [HEIGHT_MULTIPLIER]. */
+            @JvmField public val SIZE_MULTIPLIER: Target = Target(2)
+            /**
+             * Adds the target modifier to [BrushTip.slant]. The final brush slant value is clamped
+             * to [-π/2, π/2]. If multiple behaviors have this target, they stack additively.
+             */
+            @JvmField public val SLANT_OFFSET_IN_RADIANS: Target = Target(3)
+            /**
+             * Adds the target modifier to [BrushTip.pinch]. The final brush pinch value is clamped
+             * to [0, 1]. If multiple behaviors have this target, they stack additively.
+             */
+            @JvmField public val PINCH_OFFSET: Target = Target(4)
+            /**
+             * Adds the target modifier to [BrushTip.rotation]. The final brush rotation angle is
+             * effectively normalized (mod 2π). If multiple behaviors have this target, they stack
+             * additively.
+             */
+            @JvmField public val ROTATION_OFFSET_IN_RADIANS: Target = Target(5)
+            /**
+             * Adds the target modifier to [BrushTip.cornerRounding]. The final brush corner
+             * rounding value is clamped to [0, 1]. If multiple behaviors have this target, they
+             * stack additively.
+             */
+            @JvmField public val CORNER_ROUNDING_OFFSET: Target = Target(6)
+            /**
+             * Adds the target modifier to the brush tip x position, where one distance unit is
+             * equal to the brush size.
+             */
+            @JvmField public val POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE: Target = Target(7)
+            /**
+             * Adds the target modifier to the brush tip y position, where one distance unit is
+             * equal to the brush size.
+             */
+            @JvmField public val POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE: Target = Target(8)
+            /**
+             * Moves the brush tip center forward (or backward, for negative values) from the input
+             * position, in the current direction of stroke travel, where one distance unit is equal
+             * to the brush size.
+             */
+            @JvmField
+            public val POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE: Target = Target(9)
+            /**
+             * Moves the brush tip center sideways from the input position, relative to the
+             * direction of stroke travel, where one distance unit is equal to the brush size. If
+             * the X- and Y-axes of stroke space were rotated so that the positive X-axis points in
+             * the direction of stroke travel, then a positive value for this offset moves the brush
+             * tip center towards the positive Y-axis (and a negative value moves the brush tip
+             * center towards the negative Y-axis).
+             */
+            @JvmField
+            public val POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE: Target = Target(10)
+
+            // The following are targets for tip color adjustments, including opacity. Renderers can
+            // apply
+            // them to the brush color when a stroke is drawn to contribute to the local color of
+            // each
+            // part of the stroke.
+            /**
+             * Shifts the hue of the base brush color. A positive offset shifts around the hue wheel
+             * from red towards orange, while a negative offset shifts the other way, from red
+             * towards violet. The final hue offset is not clamped, but is effectively normalized
+             * (mod 2π). If multiple behaviors have this target, they stack additively.
+             */
+            @JvmField public val HUE_OFFSET_IN_RADIANS: Target = Target(11)
+            /**
+             * Scales the saturation of the base brush color. If multiple behaviors have one of
+             * these targets, they stack multiplicatively. The final saturation multiplier is
+             * clamped to [0, 2].
+             */
+            @JvmField public val SATURATION_MULTIPLIER: Target = Target(12)
+            /**
+             * Target the luminosity of the color. An offset of +/-100% corresponds to changing the
+             * luminosity by up to +/-100%.
+             */
+            @JvmField public val LUMINOSITY: Target = Target(13)
+            /**
+             * Scales the opacity of the base brush color. If multiple behaviors have one of these
+             * targets, they stack multiplicatively. The final opacity multiplier is clamped to
+             * [0, 2].
+             */
+            @JvmField public val OPACITY_MULTIPLIER: Target = Target(14)
+
+            private const val PREFIX = "BrushBehavior.Target."
+        }
+    }
+
+    /**
+     * The desired behavior when an input value is outside the range defined by
+     * [sourceValueRangeLowerBound, sourceValueRangeUpperBound].
+     */
+    public class OutOfRange private constructor(@JvmField internal val value: Int) {
+        public fun toSimpleString(): String =
+            when (this) {
+                CLAMP -> "CLAMP"
+                REPEAT -> "REPEAT"
+                MIRROR -> "MIRROR"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + this.toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is OutOfRange) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+
+            // Values outside the range will be clamped to not exceed the bounds.
+            @JvmField public val CLAMP: OutOfRange = OutOfRange(0)
+            // Values will be shifted by an integer multiple of the range size so that they fall
+            // within
+            // the bounds.
+            //
+            // In this case, the range will be treated as a half-open interval, with a value exactly
+            // at
+            // [sourceValueRangeUpperBound] being treated as though it was
+            // [sourceValueRangeLowerBound].
+            @JvmField public val REPEAT: OutOfRange = OutOfRange(1)
+            // Similar to [Repeat], but every other repetition of the bounds will be mirrored, as
+            // though
+            // the
+            // two elements [sourceValueRangeLowerBound] and [sourceValueRangeUpperBound] were
+            // swapped.
+            // This means the range does not need to be treated as a half-open interval like in the
+            // case
+            // of [Repeat].
+            @JvmField public val MIRROR: OutOfRange = OutOfRange(2)
+            private const val PREFIX = "BrushBehavior.OutOfRange."
+        }
+    }
+
+    /** List of input properties that might not be reported by inputs. */
+    public class OptionalInputProperty private constructor(@JvmField internal val value: Int) {
+
+        public fun toSimpleString(): String =
+            when (this) {
+                PRESSURE -> "PRESSURE"
+                TILT -> "TILT"
+                ORIENTATION -> "ORIENTATION"
+                TILT_X_AND_Y -> "TILT_X_AND_Y"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + this.toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is OptionalInputProperty) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+
+            @JvmField public val PRESSURE: OptionalInputProperty = OptionalInputProperty(0)
+            @JvmField public val TILT: OptionalInputProperty = OptionalInputProperty(1)
+            @JvmField public val ORIENTATION: OptionalInputProperty = OptionalInputProperty(2)
+            /** Tilt-x and tilt-y require both tilt and orientation to be reported. */
+            @JvmField public val TILT_X_AND_Y: OptionalInputProperty = OptionalInputProperty(3)
+            private const val PREFIX = "BrushBehavior.OptionalInputProperty."
+        }
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushCoat.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushCoat.kt
new file mode 100644
index 0000000..1582b57
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushCoat.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import androidx.ink.nativeloader.NativeLoader
+import java.util.Collections.unmodifiableList
+import kotlin.jvm.JvmOverloads
+import kotlin.jvm.JvmStatic
+
+/**
+ * A [BrushCoat] represents one coat of paint applied by a brush. It includes a single [BrushPaint],
+ * as well as one or more [BrushTip]s used to apply that paint. Multiple [BrushCoat] can be combined
+ * within a single brush; when a stroke drawn by a multi-coat brush is rendered, each coat of paint
+ * will be drawn entirely atop the previous coat, even if the stroke crosses over itself, as though
+ * each coat were painted in its entirety one at a time.
+ */
+@ExperimentalInkCustomBrushApi
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+public class BrushCoat
+@JvmOverloads
+constructor(
+    // The [tips] val below is a defensive copy of this parameter.
+    tips: List,
+    /** The paint to be applied in this coat. */
+    public val paint: BrushPaint = BrushPaint(),
+) {
+
+    /**
+     * The tip(s) used to apply the paint.
+     *
+     * For now, there must be exactly one tip. This restriction is expected to be lifted in a future
+     * release.
+     */
+    // TODO: b/285594469 - More than one tip.
+    public val tips: List = unmodifiableList(tips.toList())
+
+    @JvmOverloads
+    public constructor(
+        tip: BrushTip = BrushTip(),
+        paint: BrushPaint = BrushPaint(),
+    ) : this(listOf(tip), paint)
+
+    /** A handle to the underlying native [BrushCoat] object. */
+    internal val nativePointer: Long =
+        nativeCreateBrushCoat(tips.map { it.nativePointer }.toLongArray(), paint.nativePointer)
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @JvmSynthetic
+    public fun copy(tips: List = this.tips, paint: BrushPaint = this.paint): BrushCoat {
+        return if (tips == this.tips && paint == this.paint) {
+            this
+        } else {
+            BrushCoat(tips, paint)
+        }
+    }
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @JvmSynthetic
+    public fun copy(tip: BrushTip, paint: BrushPaint = this.paint): BrushCoat {
+        return if (this.tips.size == 1 && tip == this.tips[0] && paint == this.paint) {
+            this
+        } else {
+            BrushCoat(tip, paint)
+        }
+    }
+
+    /**
+     * Returns a [Builder] with values set equivalent to `this`. Java developers, use the returned
+     * builder to build a copy of a BrushCoat.
+     */
+    public fun toBuilder(): Builder = Builder().setTips(tips).setPaint(paint)
+
+    /**
+     * Builder for [BrushCoat].
+     *
+     * For Java developers, use BrushCoat.Builder to construct [BrushCoat] with default values,
+     * overriding only as needed. For example: `BrushCoat family = new
+     * BrushCoat.Builder().tip(presetBrushTip).build();`
+     */
+    public class Builder {
+        private var tips: List = listOf(BrushTip())
+        private var paint: BrushPaint = BrushPaint()
+
+        public fun setTip(tip: BrushTip): Builder {
+            this.tips = listOf(tip)
+            return this
+        }
+
+        public fun setTips(tips: List): Builder {
+            this.tips = tips.toList()
+            return this
+        }
+
+        public fun setPaint(paint: BrushPaint): Builder {
+            this.paint = paint
+            return this
+        }
+
+        public fun build(): BrushCoat = BrushCoat(tips, paint)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other == null || other !is BrushCoat) return false
+        return tips == other.tips && paint == other.paint
+    }
+
+    override fun hashCode(): Int {
+        var result = tips.hashCode()
+        result = 31 * result + paint.hashCode()
+        return result
+    }
+
+    override fun toString(): String = "BrushCoat(tips=$tips, paint=$paint)"
+
+    /** Deletes native BrushCoat memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrushCoat(nativePointer)
+    }
+
+    /** Create underlying native object and return reference for all subsequent native calls. */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushCoat(
+        tipNativePointers: LongArray,
+        paintNativePointer: Long,
+    ): Long
+
+    /** Release the underlying memory allocated in [nativeCreateBrushCoat]. */
+    private external fun nativeFreeBrushCoat(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    // Companion object gets initialized before anything else.
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+
+        /** Returns a new [BrushCoat.Builder]. */
+        @JvmStatic public fun builder(): Builder = Builder()
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushFamily.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushFamily.kt
new file mode 100644
index 0000000..5f6d9f9
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushFamily.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import androidx.ink.nativeloader.NativeLoader
+import java.util.Collections.unmodifiableList
+import kotlin.jvm.JvmOverloads
+import kotlin.jvm.JvmStatic
+
+/**
+ * A [BrushFamily] combines one or more [BrushCoat]s and an optional URI to describe a family of
+ * brushes.
+ *
+ * The [uri] exists for the convenience of higher level serialization and asset management APIs.
+ * Aside from being checked for valid formatting and being forwarded on copy or move, the [uri] will
+ * not*** be used by Ink APIs that consume a [BrushFamily].
+ */
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+public class BrushFamily
+@ExperimentalInkCustomBrushApi
+@JvmOverloads
+constructor(
+    // The [coats] val below is a defensive copy of this parameter.
+    coats: List,
+    public val uri: String? = null,
+) {
+    public val coats: List = unmodifiableList(coats.toList())
+
+    @ExperimentalInkCustomBrushApi
+    @JvmOverloads
+    public constructor(
+        tip: BrushTip = BrushTip(),
+        paint: BrushPaint = BrushPaint(),
+        uri: String? = null,
+    ) : this(listOf(BrushCoat(tip, paint)), uri)
+
+    /** A handle to the underlying native [BrushFamily] object. */
+    internal val nativePointer: Long =
+        nativeCreateBrushFamily(coats.map { it.nativePointer }.toLongArray(), uri)
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @ExperimentalInkCustomBrushApi
+    @JvmSynthetic
+    public fun copy(coats: List = this.coats, uri: String? = this.uri): BrushFamily {
+        return if (coats == this.coats && uri == this.uri) {
+            this
+        } else {
+            BrushFamily(coats, uri)
+        }
+    }
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @ExperimentalInkCustomBrushApi
+    @JvmSynthetic
+    public fun copy(coat: BrushCoat, uri: String? = this.uri): BrushFamily {
+        return copy(coats = listOf(coat), uri = uri)
+    }
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @ExperimentalInkCustomBrushApi
+    @JvmSynthetic
+    public fun copy(tip: BrushTip, paint: BrushPaint, uri: String? = this.uri): BrushFamily {
+        return copy(coat = BrushCoat(tip, paint), uri = uri)
+    }
+
+    /**
+     * Returns a [Builder] with values set equivalent to `this`. Java developers, use the returned
+     * builder to build a copy of a BrushFamily.
+     */
+    @ExperimentalInkCustomBrushApi
+    public fun toBuilder(): Builder = Builder().setCoats(coats).setUri(uri)
+
+    /**
+     * Builder for [BrushFamily].
+     *
+     * For Java developers, use BrushFamily.Builder to construct [BrushFamily] with default values,
+     * overriding only as needed. For example: `BrushFamily family = new
+     * BrushFamily.Builder().coat(presetBrushCoat).build();`
+     */
+    @ExperimentalInkCustomBrushApi
+    public class Builder {
+        private var coats: List = listOf(BrushCoat(BrushTip(), BrushPaint()))
+        private var uri: String? = null
+
+        public fun setCoat(tip: BrushTip, paint: BrushPaint): Builder =
+            setCoat(BrushCoat(tip, paint))
+
+        public fun setCoat(coat: BrushCoat): Builder = setCoats(listOf(coat))
+
+        public fun setCoats(coats: List): Builder {
+            this.coats = coats.toList()
+            return this
+        }
+
+        public fun setUri(uri: String?): Builder {
+            this.uri = uri
+            return this
+        }
+
+        public fun build(): BrushFamily = BrushFamily(coats, uri)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other == null || other !is BrushFamily) return false
+        return coats == other.coats && uri == other.uri
+    }
+
+    override fun hashCode(): Int {
+        var result = coats.hashCode()
+        result = 31 * result + uri.hashCode()
+        return result
+    }
+
+    override fun toString(): String = "BrushFamily(coats=$coats, uri=$uri)"
+
+    /** Deletes native BrushFamily memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrushFamily(nativePointer)
+    }
+
+    /** Create underlying native object and return reference for all subsequent native calls. */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushFamily(coatNativePointers: LongArray, uri: String?): Long
+
+    /** Release the underlying memory allocated in [nativeCreateBrushFamily]. */
+    private external fun nativeFreeBrushFamily(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    // Companion object gets initialized before anything else.
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+
+        /** Returns a new [BrushFamily.Builder]. */
+        @ExperimentalInkCustomBrushApi @JvmStatic public fun builder(): Builder = Builder()
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushPaint.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushPaint.kt
new file mode 100644
index 0000000..71a93b8
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushPaint.kt
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.FloatRange
+import androidx.annotation.RestrictTo
+import androidx.ink.geometry.AngleRadiansFloat
+import androidx.ink.nativeloader.NativeLoader
+import java.util.Collections.unmodifiableList
+import kotlin.Suppress
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmSynthetic
+
+/**
+ * Parameters that control stroke mesh rendering. Note: This contains only a subset of the
+ * parameters as support is added for them.
+ *
+ * The core of each paint consists of one or more texture layers. The output of each layer is
+ * blended together in sequence, then the combined texture is blended with the output from the brush
+ * color.
+ * - Starting with the first [TextureLayer], the combined texture for layers 0 to i (source) is
+ *   blended with layer i+1 (destination) using the blend mode for layer i.
+ * - The final combined texture (source) is blended with the (possibly adjusted per-vertex) brush
+ *   color (destination) according to the blend mode of the last texture layer.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@ExperimentalInkCustomBrushApi
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+public class BrushPaint(
+    // The [textureLayers] val below is a defensive copy of this parameter.
+    textureLayers: List = emptyList()
+) {
+    /** The textures to apply to the stroke. */
+    public val textureLayers: List = unmodifiableList(textureLayers.toList())
+
+    /** A handle to the underlying native [BrushPaint] object. */
+    internal val nativePointer: Long = nativeCreateBrushPaint(textureLayers.size)
+
+    init {
+        for (layer in textureLayers) {
+            nativeAppendTextureLayer(nativePointer, layer.nativePointer)
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is BrushPaint) return false
+        return textureLayers == other.textureLayers
+    }
+
+    override fun toString(): String = "BrushPaint(textureLayers=$textureLayers)"
+
+    override fun hashCode(): Int {
+        return textureLayers.hashCode()
+    }
+
+    /** Delete native BrushPaint memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrushPaint(nativePointer)
+    }
+
+    /** Create underlying native object and return reference for all subsequent native calls. */
+    private external fun nativeCreateBrushPaint(
+        textureLayersCount: Int
+    ): Long // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /**
+     * Appends a texture layer to a *mutable* C++ BrushPaint object as referenced by
+     * [nativePointer]. Only call during `init{}` so to keep this BrushPaint object immutable after
+     * construction and equivalent across Kotlin and C++.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeAppendTextureLayer(nativePointer: Long, textureLayerPointer: Long)
+
+    /** Release the underlying memory allocated in [nativeCreateBrushPaint]. */
+    private external fun nativeFreeBrushPaint(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /** Specification of how the texture should apply to the stroke. */
+    public class TextureMapping private constructor(@JvmField internal val value: Int) {
+        override fun toString(): String =
+            when (this) {
+                TILING -> "BrushPaint.TextureMapping.TILING"
+                WINDING -> "BrushPaint.TextureMapping.WINDING"
+                else -> "BrushPaint.TextureMapping.INVALID($value)"
+            }
+
+        override fun equals(other: Any?): Boolean {
+            if (other === this) return true
+            if (other !is TextureMapping) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+            /**
+             * The texture will repeat according to a 2D affine transformation of vertex positions.
+             * Each copy of the texture will have the same size and shape modulo reflections.
+             */
+            @JvmField public val TILING: TextureMapping = TextureMapping(0)
+            /**
+             * The texture will morph to "wind along the path of the stroke." The horizontal axis of
+             * texture space will lie along the width of the stroke and the vertical axis will lie
+             * along the direction of travel of the stroke at each point.
+             */
+            @JvmField public val WINDING: TextureMapping = TextureMapping(1)
+        }
+    }
+
+    /** Specification of the origin point to use for the texture. */
+    public class TextureOrigin private constructor(@JvmField internal val value: Int) {
+        override fun toString(): String =
+            when (this) {
+                STROKE_SPACE_ORIGIN -> "BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN"
+                FIRST_STROKE_INPUT -> "BrushPaint.TextureOrigin.FIRST_STROKE_INPUT"
+                LAST_STROKE_INPUT -> "BrushPaint.TextureOrigin.LAST_STROKE_INPUT"
+                else -> "BrushPaint.TextureOrigin.INVALID($value)"
+            }
+
+        override fun equals(other: Any?): Boolean {
+            if (other === this) return true
+            if (other !is TextureOrigin) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+            /**
+             * The texture origin is the origin of stroke space, however that happens to be defined
+             * for a given stroke.
+             */
+            @JvmField public val STROKE_SPACE_ORIGIN: TextureOrigin = TextureOrigin(0)
+            /** The texture origin is the first input position for the stroke. */
+            @JvmField public val FIRST_STROKE_INPUT: TextureOrigin = TextureOrigin(1)
+            /**
+             * The texture origin is the last input position (including predicted inputs) for the
+             * stroke. Note that this means that the texture origin for an in-progress stroke will
+             * move as more inputs are added.
+             */
+            @JvmField public val LAST_STROKE_INPUT: TextureOrigin = TextureOrigin(2)
+        }
+    }
+
+    /** Units for specifying [TextureLayer.sizeX] and [TextureLayer.sizeY]. */
+    public class TextureSizeUnit private constructor(@JvmField internal val value: Int) {
+        override fun toString(): String =
+            when (this) {
+                BRUSH_SIZE -> "BrushPaint.TextureSizeUnit.BRUSH_SIZE"
+                STROKE_SIZE -> "BrushPaint.TextureSizeUnit.STROKE_SIZE"
+                STROKE_COORDINATES -> "BrushPaint.TextureSizeUnit.STROKE_COORDINATES"
+                else -> "BrushPaint.TextureSizeUnit.INVALID($value)"
+            }
+
+        override fun equals(other: Any?): Boolean {
+            if (other === this) return true
+            if (other !is TextureSizeUnit) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+            /** As multiples of brush size. */
+            @JvmField public val BRUSH_SIZE: TextureSizeUnit = TextureSizeUnit(0)
+            /**
+             * As multiples of the stroke "size". This has different meanings depending on the value
+             * of [TextureMapping] for the given texture. For [TextureMapping.TILING] textures, the
+             * stroke size is equal to the dimensions of the XY bounding rectangle of the mesh. For
+             * [TextureMapping.WINDING] textures, the stroke size components are given by x: stroke
+             * width, which may change over the course of the stroke if behaviors affect the tip
+             * geometry. y: the total distance traveled by the stroke.
+             */
+            @JvmField public val STROKE_SIZE: TextureSizeUnit = TextureSizeUnit(1)
+            /** In the same units as the stroke's input positions and stored geometry. */
+            @JvmField public val STROKE_COORDINATES: TextureSizeUnit = TextureSizeUnit(2)
+        }
+    }
+
+    /**
+     * The method by which the combined texture layers (index <= i) are blended with the next layer.
+     * The blend mode on the final layer controls how the combined texture is blended with the brush
+     * color, and should typically be a mode whose output alpha is proportional to the destination
+     * alpha, so that it can be adjusted by anti-aliasing.
+     */
+    public class BlendMode private constructor(@JvmField internal val value: Int) {
+        override fun toString(): String =
+            when (this) {
+                MODULATE -> "BrushPaint.BlendMode.MODULATE"
+                DST_IN -> "BrushPaint.BlendMode.DST_IN"
+                DST_OUT -> "BrushPaint.BlendMode.DST_OUT"
+                SRC_ATOP -> "BrushPaint.BlendMode.SRC_ATOP"
+                SRC_IN -> "BrushPaint.BlendMode.SRC_IN"
+                SRC_OVER -> "BrushPaint.BlendMode.SRC_OVER"
+                else -> "BrushPaint.BlendMode.INVALID($value)"
+            }
+
+        override fun equals(other: Any?): Boolean {
+            if (other === this) return true
+            return other is BlendMode && this.value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+
+            /**
+             * Source and destination are component-wise multiplied, including opacity.
+             *
+             * ```
+             * Alpha = Alpha_src * Alpha_dst
+             * Color = Color_src * Color_dst
+             * ```
+             */
+            @JvmField public val MODULATE: BlendMode = BlendMode(0)
+            /**
+             * Keeps destination pixels that cover source pixels. Discards remaining source and
+             * destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_src * Alpha_dst
+             * Color = Alpha_src * Color_dst
+             * ```
+             */
+            @JvmField public val DST_IN: BlendMode = BlendMode(1)
+            /**
+             * Keeps the destination pixels not covered by source pixels. Discards destination
+             * pixels that are covered by source pixels and all source pixels.
+             *
+             * ```
+             * Alpha = (1 - Alpha_src) * Alpha_dst
+             * Color = (1 - Alpha_src) * Color_dst
+             * ```
+             */
+            @JvmField public val DST_OUT: BlendMode = BlendMode(2)
+            /**
+             * Discards source pixels that do not cover destination pixels. Draws remaining pixels
+             * over destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_dst
+             * Color = Alpha_dst * Color_src + (1 - Alpha_src) * Color_dst
+             * ```
+             */
+            @JvmField public val SRC_ATOP: BlendMode = BlendMode(3)
+            /**
+             * Keeps the source pixels that cover destination pixels. Discards remaining source and
+             * destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_src * Alpha_dst
+             * Color = Color_src * Alpha_dst
+             * ```
+             */
+            @JvmField public val SRC_IN: BlendMode = BlendMode(4)
+
+            /*
+             * The following modes can't be used for the last TextureLayer, which defines the mode for
+             * blending the combined texture with the (possibly adjusted per-vertex) brush color. That blend
+             * mode needs the output Alpha to be a multiple of Alpha_dst so that per-vertex adjustment for
+             * anti-aliasing is preserved correctly.
+             */
+
+            /**
+             * The source pixels are drawn over the destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_src + (1 - Alpha_src) * Alpha_dst
+             * Color = Color_src + (1 - Alpha_src) * Color_dst
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val SRC_OVER: BlendMode = BlendMode(5)
+            /**
+             * The source pixels are drawn behind the destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_dst + (1 - Alpha_dst) * Alpha_src
+             * Color = Color_dst + (1 - Alpha_dst) * Color_src
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val DST_OVER: BlendMode = BlendMode(6)
+            /**
+             * Keeps the source pixels and discards the destination pixels.
+             *
+             * ```
+             * Alpha = Alpha_src
+             * Color = Color_src
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val SRC: BlendMode = BlendMode(7)
+            /**
+             * Keeps the destination pixels and discards the source pixels.
+             *
+             * ```
+             * Alpha = Alpha_dst
+             * Color = Color_dst
+             * ```
+             *
+             * This mode is unlikely to be useful, since it effectively causes the renderer to just
+             * ignore this [TextureLayer] and all layers before it, but it is included for
+             * completeness.
+             */
+            @JvmField public val DST: BlendMode = BlendMode(8)
+            /**
+             * Keeps the source pixels that do not cover destination pixels. Discards destination
+             * pixels and all source pixels that cover destination pixels.
+             *
+             * ```
+             * Alpha = (1 - Alpha_dst) * Alpha_src
+             * Color = (1 - Alpha_dst) * Color_src
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val SRC_OUT: BlendMode = BlendMode(9)
+            /**
+             * Discards destination pixels that aren't covered by source pixels. Remaining
+             * destination pixels are drawn over source pixels.
+             *
+             * ```
+             * Alpha = Alpha_src
+             * Color = Alpha_src * Color_dst + (1 - Alpha_dst) * Color_src
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val DST_ATOP: BlendMode = BlendMode(10)
+            /**
+             * Discards source and destination pixels that intersect; keeps source and destination
+             * pixels that do not intersect.
+             *
+             * ```
+             * Alpha = (1 - Alpha_dst) * Alpha_src + (1 - Alpha_src) * Alpha_dst
+             * Color = (1 - Alpha_dst) * Color_src + (1 - Alpha_src) * Color_dst
+             * ```
+             *
+             * This mode shouldn't normally be used for the final [TextureLayer], since its output
+             * alpha is not proportional to the destination alpha (so it wouldn't preserve alpha
+             * adjustments from anti-aliasing).
+             */
+            @JvmField public val XOR: BlendMode = BlendMode(11)
+        }
+    }
+
+    /**
+     * An explicit layer defined by an image.
+     *
+     * @param colorTextureUri The URI of an image that provides the color for a particular pixel for
+     *   this layer. The coordinates within this image that will be used are determined by the other
+     *   parameters.
+     * @param sizeX The X size in [TextureSizeUnit] of the image specified by [colorTextureUri].
+     * @param sizeY The Y size in [TextureSizeUnit] of the image specified by [colorTextureUri].
+     * @param offsetX An offset into the texture, specified as fractions of the texture [sizeX] in
+     *   the range [0,1].
+     * @param offsetY An offset into the texture, specified as fractions of the texture [sizeY] in
+     *   the range [0,1].
+     * @param rotation Angle in radians specifying the rotation of the texture. The rotation is
+     *   carried out about the center of the texture's first repetition along both axes.
+     * @param opacity Overall layer opacity in the range [0,1], where 0 is transparent and 1 is
+     *   opaque.
+     * @param sizeUnit The units used to specify [sizeX] and [sizeY].
+     * @param mapping The method by which the coordinates of the [colorTextureUri] image will apply
+     *   to the stroke.
+     * @param blendMode The method by which the texture layers up to this one (index <= i) are
+     *   combined with the subsequent texture layer (index == i+1). For the last texture layer, this
+     *   defines the method by which the texture layer is combined with the brush color (possibly
+     *   after that color gets per-vertex adjustments).
+     */
+    @Suppress("NotCloseable") // Finalize is only used to free the native peer.
+    public class TextureLayer(
+        public val colorTextureUri: String,
+        @FloatRange(
+            from = 0.0,
+            fromInclusive = false,
+            to = Double.POSITIVE_INFINITY,
+            toInclusive = false
+        )
+        public val sizeX: Float,
+        @FloatRange(
+            from = 0.0,
+            fromInclusive = false,
+            to = Double.POSITIVE_INFINITY,
+            toInclusive = false
+        )
+        public val sizeY: Float,
+        @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+        public val offsetX: Float = 0f,
+        @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+        public val offsetY: Float = 0f,
+        @AngleRadiansFloat public val rotation: Float = 0F,
+        @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+        public val opacity: Float = 1f,
+        public val sizeUnit: TextureSizeUnit = TextureSizeUnit.STROKE_COORDINATES,
+        public val origin: TextureOrigin = TextureOrigin.STROKE_SPACE_ORIGIN,
+        public val mapping: TextureMapping = TextureMapping.TILING,
+        public val blendMode: BlendMode = BlendMode.MODULATE,
+    ) {
+        internal val nativePointer: Long =
+            nativeCreateTextureLayer(
+                colorTextureUri,
+                sizeX,
+                sizeY,
+                offsetX,
+                offsetY,
+                rotation,
+                opacity,
+                sizeUnit.value,
+                origin.value,
+                mapping.value,
+                blendMode.value,
+            )
+
+        /**
+         * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+         * unchanged.
+         */
+        @JvmSynthetic
+        public fun copy(
+            colorTextureUri: String = this.colorTextureUri,
+            sizeX: Float = this.sizeX,
+            sizeY: Float = this.sizeY,
+            offsetX: Float = this.offsetX,
+            offsetY: Float = this.offsetY,
+            @AngleRadiansFloat rotation: Float = this.rotation,
+            opacity: Float = this.opacity,
+            sizeUnit: TextureSizeUnit = this.sizeUnit,
+            origin: TextureOrigin = this.origin,
+            mapping: TextureMapping = this.mapping,
+            blendMode: BlendMode = this.blendMode,
+        ): TextureLayer {
+            if (
+                colorTextureUri == this.colorTextureUri &&
+                    sizeX == this.sizeX &&
+                    sizeY == this.sizeY &&
+                    offsetX == this.offsetX &&
+                    offsetY == this.offsetY &&
+                    rotation == this.rotation &&
+                    opacity == this.opacity &&
+                    sizeUnit == this.sizeUnit &&
+                    origin == this.origin &&
+                    mapping == this.mapping &&
+                    blendMode == this.blendMode
+            ) {
+                return this
+            }
+            return TextureLayer(
+                colorTextureUri,
+                sizeX,
+                sizeY,
+                offsetX,
+                offsetY,
+                rotation,
+                opacity,
+                sizeUnit,
+                origin,
+                mapping,
+                blendMode,
+            )
+        }
+
+        /**
+         * Returns a [Builder] with values set equivalent to `this`. Java developers, use the
+         * returned builder to build a copy of a TextureLayer. Kotlin developers, see [copy] method.
+         */
+        public fun toBuilder(): Builder =
+            Builder(
+                colorTextureUri = this.colorTextureUri,
+                sizeX = this.sizeX,
+                sizeY = this.sizeY,
+                offsetX = this.offsetX,
+                offsetY = this.offsetY,
+                rotation = this.rotation,
+                opacity = this.opacity,
+                sizeUnit = this.sizeUnit,
+                origin = this.origin,
+                mapping = this.mapping,
+                blendMode = this.blendMode,
+            )
+
+        override fun equals(other: Any?): Boolean {
+            if (other !is TextureLayer) return false
+            return colorTextureUri == other.colorTextureUri &&
+                sizeX == other.sizeX &&
+                sizeY == other.sizeY &&
+                offsetX == other.offsetX &&
+                offsetY == other.offsetY &&
+                rotation == other.rotation &&
+                opacity == other.opacity &&
+                sizeUnit == other.sizeUnit &&
+                origin == other.origin &&
+                mapping == other.mapping &&
+                blendMode == other.blendMode
+        }
+
+        override fun toString(): String =
+            "BrushPaint.TextureLayer(colorTextureUri=$colorTextureUri, sizeX=$sizeX, sizeY=$sizeY, " +
+                "offset=[$offsetX, $offsetY], rotation=$rotation, opacity=$opacity sizeUnit=$sizeUnit, origin=$origin, mapping=$mapping, " +
+                "blendMode=$blendMode)"
+
+        override fun hashCode(): Int {
+            var result = colorTextureUri.hashCode()
+            result = 31 * result + sizeX.hashCode()
+            result = 31 * result + sizeY.hashCode()
+            result = 31 * result + offsetX.hashCode()
+            result = 31 * result + offsetY.hashCode()
+            result = 31 * result + rotation.hashCode()
+            result = 31 * result + opacity.hashCode()
+            result = 31 * result + sizeUnit.hashCode()
+            result = 31 * result + origin.hashCode()
+            result = 31 * result + mapping.hashCode()
+            result = 31 * result + blendMode.hashCode()
+            return result
+        }
+
+        /** Delete native TextureLayer memory. */
+        protected fun finalize() {
+            // NOMUTANTS -- Not tested post garbage collection.
+            nativeFreeTextureLayer(nativePointer)
+        }
+
+        /**
+         * Builder for [TextureLayer].
+         *
+         * Construct from TextureLayer.toBuilder().
+         */
+        @Suppress(
+            "ScopeReceiverThis"
+        ) // Builder pattern supported for Java clients, despite being an anti-pattern in Kotlin.
+        public class Builder
+        internal constructor(
+            private var colorTextureUri: String,
+            @FloatRange(
+                from = 0.0,
+                fromInclusive = false,
+                to = Double.POSITIVE_INFINITY,
+                toInclusive = false
+            )
+            private var sizeX: Float,
+            @FloatRange(
+                from = 0.0,
+                fromInclusive = false,
+                to = Double.POSITIVE_INFINITY,
+                toInclusive = false
+            )
+            private var sizeY: Float,
+            @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+            private var offsetX: Float = 0f,
+            @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+            private var offsetY: Float = 0f,
+            @AngleRadiansFloat private var rotation: Float = 0F,
+            @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+            private var opacity: Float = 1f,
+            private var sizeUnit: TextureSizeUnit = TextureSizeUnit.STROKE_COORDINATES,
+            private var origin: TextureOrigin = TextureOrigin.STROKE_SPACE_ORIGIN,
+            private var mapping: TextureMapping = TextureMapping.TILING,
+            private var blendMode: BlendMode = BlendMode.MODULATE,
+        ) {
+            public fun setColorTextureUri(colorTextureUri: String): Builder = apply {
+                this.colorTextureUri = colorTextureUri
+            }
+
+            public fun setSizeX(sizeX: Float): Builder = apply { this.sizeX = sizeX }
+
+            public fun setSizeY(sizeY: Float): Builder = apply { this.sizeY = sizeY }
+
+            public fun setOffsetX(offsetX: Float): Builder = apply { this.offsetX = offsetX }
+
+            public fun setOffsetY(offsetY: Float): Builder = apply { this.offsetY = offsetY }
+
+            public fun setRotation(rotation: Float): Builder = apply { this.rotation = rotation }
+
+            public fun setOpacity(opacity: Float): Builder = apply { this.opacity = opacity }
+
+            public fun setSizeUnit(sizeUnit: TextureSizeUnit): Builder = apply {
+                this.sizeUnit = sizeUnit
+            }
+
+            public fun setOrigin(origin: TextureOrigin): Builder = apply { this.origin = origin }
+
+            public fun setMapping(mapping: TextureMapping): Builder = apply {
+                this.mapping = mapping
+            }
+
+            public fun setBlendMode(blendMode: BlendMode): Builder = apply {
+                this.blendMode = blendMode
+            }
+
+            public fun build(): TextureLayer =
+                TextureLayer(
+                    colorTextureUri,
+                    sizeX,
+                    sizeY,
+                    offsetX,
+                    offsetY,
+                    rotation,
+                    opacity,
+                    sizeUnit,
+                    origin,
+                    mapping,
+                    blendMode,
+                )
+        }
+
+        // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+        private external fun nativeCreateTextureLayer(
+            colorTextureUri: String,
+            sizeX: Float,
+            sizeY: Float,
+            offsetX: Float,
+            offsetY: Float,
+            rotation: Float,
+            opacity: Float,
+            sizeUnit: Int,
+            origin: Int,
+            mapping: Int,
+            blendMode: Int,
+        ): Long
+
+        /** Release the underlying memory allocated in [nativeCreateTextureLayer]. */
+        private external fun nativeFreeTextureLayer(
+            nativePointer: Long
+        ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+        // To be extended by extension methods.
+        public companion object
+    }
+
+    // To be extended by extension methods.
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushTip.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushTip.kt
new file mode 100644
index 0000000..e226874
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/BrushTip.kt
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.FloatRange
+import androidx.annotation.IntRange
+import androidx.annotation.RestrictTo
+import androidx.ink.geometry.Angle
+import androidx.ink.geometry.AngleRadiansFloat
+import androidx.ink.nativeloader.NativeLoader
+import java.util.Collections.unmodifiableList
+import kotlin.jvm.JvmStatic
+import kotlin.jvm.JvmSynthetic
+import kotlin.math.PI
+
+/**
+ * A [BrushTip] consists of parameters that control how stroke inputs are used to model the tip
+ * shape and color, and create vertices for the stroke mesh.
+ *
+ * The specification can be considered in two parts:
+ * 1. Parameters for the base shape of the tip as a function of [Brush] size.
+ * 2. An array of [BrushBehavior]s that allow dynamic properties of each input to augment the tip
+ *    shape and color.
+ *
+ * Depending on the combination of values, the tip can be shaped as a rounded parallelogram, circle,
+ * or stadium. Through [BrushBehavior]s, the tip can produce a per-vertex HSLA color shift that can
+ * be used to augment the [Brush] color when drawing. The default values below produce a static
+ * circular tip shape with diameter equal to the [Brush] size and no color shift.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@ExperimentalInkCustomBrushApi
+@Suppress("NotCloseable") // Finalize is only used to free the native peer.
+public class BrushTip(
+    /**
+     * 2D scale used to calculate the initial width and height of the tip shape relative to the
+     * brush size prior to applying [slant] and [rotation].
+     *
+     * The base width and height of the tip will be equal to the brush size multiplied by [scaleX]
+     * and [scaleY] respectively. Valid values must be finite and non-negative, with at least one
+     * value greater than zero.
+     */
+    @FloatRange(
+        from = 0.0,
+        fromInclusive = true,
+        to = Double.POSITIVE_INFINITY,
+        toInclusive = false
+    )
+    public val scaleX: Float = 1f,
+
+    /**
+     * 2D scale used to calculate the initial width and height of the tip shape relative to the
+     * brush size prior to applying [slant] and [rotation].
+     *
+     * The base width and height of the tip will be equal to the brush size multiplied by [scaleX]
+     * and [scaleY] respectively. Valid values must be finite and non-negative, with at least one
+     * value greater than zero.
+     */
+    @FloatRange(
+        from = 0.0,
+        fromInclusive = true,
+        to = Double.POSITIVE_INFINITY,
+        toInclusive = false
+    )
+    public val scaleY: Float = 1f,
+
+    /**
+     * A normalized value in the range [0, 1] that is used to calculate the initial radius of
+     * curvature for the tip's corners. A value of 0 results in sharp corners and a value of 1
+     * results in the maximum radius of curvature given the current tip dimensions.
+     */
+    @FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
+    public val cornerRounding: Float = 1f,
+
+    /**
+     * Angle in readians used to calculate the initial slant of the tip shape prior to applying
+     * [rotation].
+     *
+     * The value should be in the range [-π/2, π/2] radians, and represents the angle by which
+     * "vertical" lines of the tip shape will appear rotated about their intersection with the
+     * x-axis.
+     *
+     * More info: This property is similar to the single-arg CSS skew() transformation. Unlike skew,
+     * slant tries to preserve the perimeter of the tip shape as opposed to its area. This is akin
+     * to "pressing" a rectangle into a parallelogram with non-right angles while preserving the
+     * side lengths.
+     */
+    @FloatRange(from = -PI / 2, fromInclusive = true, to = PI / 2, toInclusive = true)
+    @AngleRadiansFloat
+    public val slant: Float = Angle.ZERO,
+
+    /**
+     * A unitless parameter in the range [0, 1] that controls the separation between two of the
+     * shape's corners prior to applying [rotation].
+     *
+     * The two corners affected lie toward the negative y-axis relative to the center of the tip
+     * shape. I.e. the "upper edge" of the shape if positive y is chosen to point "down" in stroke
+     * coordinates.
+     *
+     * If [scaleX] is not 0, different values of [pinch] produce the following shapes: A value of 0
+     * will leave the corners unaffected as a rectangle or parallelogram. Values between 0 and 1
+     * will bring the corners closer together to result in a (possibly slanted) trapezoidal shape. A
+     * value of 1 will make the two corners coincide and result in a triangular shape.
+     */
+    @FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
+    public val pinch: Float = 0f,
+
+    /**
+     * Angle in radians specifying the initial rotation of the tip shape after applying [scaleX],
+     * [scaleY], [pinch], and [slant].
+     */
+    @AngleRadiansFloat public val rotation: Float = Angle.ZERO,
+
+    /**
+     * Scales the opacity of the base brush color for this tip, independent of `brush_behavior`s. A
+     * possible example application is a highlighter brush.
+     *
+     * The multiplier must be in the range [0, 2] and the value ultimately applied can be modified
+     * by applicable `brush_behavior`s.
+     */
+    @FloatRange(from = 0.0, fromInclusive = true, to = 2.0, toInclusive = true)
+    public val opacityMultiplier: Float = 1f,
+
+    /**
+     * Parameter controlling emission of particles as a function of distance traveled by the stroke
+     * inputs.
+     *
+     * When this and [particleGapDurationMillis] are both zero, the stroke will be continuous,
+     * unless gaps are introduced dynamically by [BrushBehavior]s. Otherwise, the stroke will be
+     * made up of particles. A new particle will be emitted after at least
+     * [particleGapDistanceScale] * [Brush.size] distance has been traveled by the stoke inputs.
+     */
+    @FloatRange(
+        from = 0.0,
+        fromInclusive = true,
+        to = Double.POSITIVE_INFINITY,
+        toInclusive = false
+    )
+    public val particleGapDistanceScale: Float = 0f,
+
+    /**
+     * Parameter controlling emission of particles as a function of time elapsed along the stroke.
+     *
+     * When this and [particleGapDistanceScale] are both zero, the stroke will be continuous, unless
+     * gaps are introduced dynamically by `BrushBehavior`s. Otherwise, the stroke will be made up of
+     * particles. Particles will be emitted at most once every [particleGapDurationMillis].
+     */
+    @IntRange(from = 0L) public val particleGapDurationMillis: Long = 0L,
+
+    // The [behaviors] val below is a defensive copy of this parameter.
+    behaviors: List = emptyList(),
+) {
+    /**
+     * A list of [BrushBehavior]s that allow dynamic properties of each input to augment the tip
+     * shape and color.
+     */
+    public val behaviors: List = unmodifiableList(behaviors.toList())
+
+    /** A handle to the underlying native [BrushTip] object. */
+    internal val nativePointer: Long =
+        nativeCreateBrushTip(
+            scaleX,
+            scaleY,
+            cornerRounding,
+            slant,
+            pinch,
+            rotation,
+            opacityMultiplier,
+            particleGapDistanceScale,
+            particleGapDurationMillis,
+            behaviors.size,
+        )
+
+    init {
+        for (behavior in behaviors) {
+            nativeAppendBehavior(nativePointer, behavior.nativePointer)
+        }
+    }
+
+    /**
+     * Creates a copy of `this` and allows named properties to be altered while keeping the rest
+     * unchanged.
+     */
+    @JvmSynthetic
+    public fun copy(
+        scaleX: Float = this.scaleX,
+        scaleY: Float = this.scaleY,
+        cornerRounding: Float = this.cornerRounding,
+        @AngleRadiansFloat slant: Float = this.slant,
+        pinch: Float = this.pinch,
+        @AngleRadiansFloat rotation: Float = this.rotation,
+        opacityMultiplier: Float = this.opacityMultiplier,
+        particleGapDistanceScale: Float = this.particleGapDistanceScale,
+        particleGapDurationMillis: Long = this.particleGapDurationMillis,
+        behaviors: List = this.behaviors,
+    ): BrushTip =
+        BrushTip(
+            scaleX,
+            scaleY,
+            cornerRounding,
+            slant,
+            pinch,
+            rotation,
+            opacityMultiplier,
+            particleGapDistanceScale,
+            particleGapDurationMillis,
+            behaviors,
+        )
+
+    /**
+     * Returns a [Builder] with values set equivalent to `this`. Java developers, use the returned
+     * builder to build a copy of a BrushTip. Kotlin developers, see [copy] method.
+     */
+    public fun toBuilder(): Builder =
+        Builder()
+            .setScaleX(scaleX)
+            .setScaleY(scaleY)
+            .setCornerRounding(cornerRounding)
+            .setSlant(slant)
+            .setPinch(pinch)
+            .setRotation(rotation)
+            .setOpacityMultiplier(opacityMultiplier)
+            .setParticleGapDistanceScale(particleGapDistanceScale)
+            .setParticleGapDurationMillis(particleGapDurationMillis)
+            .setBehaviors(behaviors)
+
+    /**
+     * Builder for [BrushTip].
+     *
+     * Use BrushTip.Builder to construct a [BrushTip] with default values, overriding only as
+     * needed.
+     */
+    @Suppress("ScopeReceiverThis")
+    public class Builder {
+        private var scaleX: Float = 1f
+        private var scaleY: Float = 1f
+        private var cornerRounding: Float = 1f
+        private var slant: Float = Angle.ZERO
+        private var pinch: Float = 0f
+        private var rotation: Float = Angle.ZERO
+        private var opacityMultiplier: Float = 1f
+        private var particleGapDistanceScale: Float = 0F
+        private var particleGapDurationMillis: Long = 0L
+        private var behaviors: List = emptyList()
+
+        public fun setScaleX(scaleX: Float): Builder = apply { this.scaleX = scaleX }
+
+        public fun setScaleY(scaleY: Float): Builder = apply { this.scaleY = scaleY }
+
+        public fun setCornerRounding(cornerRounding: Float): Builder = apply {
+            this.cornerRounding = cornerRounding
+        }
+
+        public fun setSlant(slant: Float): Builder = apply { this.slant = slant }
+
+        public fun setPinch(pinch: Float): Builder = apply { this.pinch = pinch }
+
+        public fun setRotation(rotation: Float): Builder = apply { this.rotation = rotation }
+
+        public fun setOpacityMultiplier(opacityMultiplier: Float): Builder = apply {
+            this.opacityMultiplier = opacityMultiplier
+        }
+
+        public fun setParticleGapDistanceScale(particleGapDistanceScale: Float): Builder = apply {
+            this.particleGapDistanceScale = particleGapDistanceScale
+        }
+
+        public fun setParticleGapDurationMillis(particleGapDurationMillis: Long): Builder = apply {
+            this.particleGapDurationMillis = particleGapDurationMillis
+        }
+
+        public fun setBehaviors(behaviors: List): Builder = apply {
+            this.behaviors = behaviors.toList()
+        }
+
+        public fun build(): BrushTip =
+            BrushTip(
+                scaleX,
+                scaleY,
+                cornerRounding,
+                slant,
+                pinch,
+                rotation,
+                opacityMultiplier,
+                particleGapDistanceScale,
+                particleGapDurationMillis,
+                behaviors,
+            )
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other == null || other !is BrushTip) return false
+        return scaleY == other.scaleY &&
+            scaleX == other.scaleX &&
+            pinch == other.pinch &&
+            cornerRounding == other.cornerRounding &&
+            slant == other.slant &&
+            rotation == other.rotation &&
+            particleGapDistanceScale == other.particleGapDistanceScale &&
+            particleGapDurationMillis == other.particleGapDurationMillis &&
+            opacityMultiplier == other.opacityMultiplier &&
+            behaviors == other.behaviors
+    }
+
+    override fun hashCode(): Int {
+        var result = scaleX.hashCode()
+        result = 31 * result + scaleY.hashCode()
+        result = 31 * result + pinch.hashCode()
+        result = 31 * result + cornerRounding.hashCode()
+        result = 31 * result + slant.hashCode()
+        result = 31 * result + rotation.hashCode()
+        result = 31 * result + opacityMultiplier.hashCode()
+        result = 31 * result + particleGapDistanceScale.hashCode()
+        result = 31 * result + particleGapDurationMillis.hashCode()
+        result = 31 * result + behaviors.hashCode()
+        return result
+    }
+
+    override fun toString(): String =
+        "BrushTip(scale=($scaleX, $scaleY), cornerRounding=$cornerRounding," +
+            " slant=$slant, pinch=$pinch, rotation=$rotation, opacityMultiplier=$opacityMultiplier," +
+            " particleGapDistanceScale=$particleGapDistanceScale," +
+            " particleGapDurationMillis=$particleGapDurationMillis, behaviors=$behaviors)"
+
+    /** Delete native BrushTip memory. */
+    protected fun finalize() {
+        // NOMUTANTS -- Not tested post garbage collection.
+        nativeFreeBrushTip(nativePointer)
+    }
+
+    /** Create underlying native object and return reference for all subsequent native calls. */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeCreateBrushTip(
+        scaleX: Float,
+        scaleY: Float,
+        cornerRounding: Float,
+        slant: Float,
+        pinch: Float,
+        rotation: Float,
+        opacityMultiplier: Float,
+        particleGapDistanceScale: Float,
+        particleGapDurationMillis: Long,
+        behaviorsCount: Int,
+    ): Long
+
+    /**
+     * Appends a texture layer to a *mutable* C++ BrushTip object as referenced by [nativePointer].
+     * Only call during init{} so to keep this BrushTip object immutable after construction and
+     * equivalent across Kotlin and C++.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun nativeAppendBehavior(tipNativePointer: Long, behaviorNativePointer: Long)
+
+    /** Release the underlying memory allocated in [nativeCreateBrushTip]. */
+    private external fun nativeFreeBrushTip(
+        nativePointer: Long
+    ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    // Companion object gets initialized before anything else.
+    public companion object {
+        init {
+            NativeLoader.load()
+        }
+
+        /** Returns a new [BrushTip.Builder]. */
+        @JvmStatic public fun builder(): Builder = Builder()
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ColorExtensions.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ColorExtensions.kt
new file mode 100644
index 0000000..889fab9
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ColorExtensions.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import androidx.ink.brush.color.Color as ComposeColor
+import androidx.ink.brush.color.colorspace.ColorSpace as ComposeColorSpace
+import androidx.ink.brush.color.colorspace.ColorSpaces as ComposeColorSpaces
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public fun ComposeColor.toColorInInkSupportedColorSpace(): ComposeColor {
+    return if (this.colorSpace.isSupportedInInk()) {
+        this
+    } else {
+        this.convert(ComposeColorSpaces.DisplayP3)
+    }
+}
+
+internal fun ComposeColorSpace.toInkColorSpaceId() =
+    when (this) {
+        ComposeColorSpaces.Srgb -> 0
+        ComposeColorSpaces.DisplayP3 -> 1
+        else -> throw IllegalArgumentException("Unsupported Compose color space")
+    }
+
+internal fun ComposeColorSpace.isSupportedInInk() =
+    (this == ComposeColorSpaces.Srgb || this == ComposeColorSpaces.DisplayP3)
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/EasingFunction.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/EasingFunction.kt
new file mode 100644
index 0000000..b39a502
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/EasingFunction.kt
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.FloatRange
+import androidx.annotation.RestrictTo
+import androidx.ink.geometry.ImmutableVec
+import java.util.Collections.unmodifiableList
+import kotlin.jvm.JvmField
+
+/**
+ * An easing function always passes through the (x, y) points (0, 0) and (1, 1). It typically acts
+ * to map x values in the [0, 1] interval to y values in [0, 1] by either one of the predefined or
+ * one of the parameterized curve types below. Depending on the type of curve, input and output
+ * values outside [0, 1] are possible.
+ */
+@ExperimentalInkCustomBrushApi
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+public abstract class EasingFunction private constructor() {
+
+    public class Predefined private constructor(@JvmField internal val value: Int) :
+        EasingFunction() {
+
+        public fun toSimpleString(): String =
+            when (value) {
+                0 -> "LINEAR"
+                1 -> "EASE"
+                2 -> "EASE_IN"
+                3 -> "EASE_OUT"
+                4 -> "EASE_IN_OUT"
+                5 -> "STEP_START"
+                6 -> "STEP_END"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is Predefined) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+            /** The linear identity function: accepts and returns values outside [0, 1]. */
+            @JvmField public val LINEAR: Predefined = Predefined(0)
+
+            /**
+             * Predefined cubic Bezier function. See
+             * [ease](https://www.w3.org/TR/css-easing-1/#cubic-bezier-easing-functions)
+             * and @see [CubicBezier] about input values outside [0, 1])
+             */
+            @JvmField public val EASE: Predefined = Predefined(1)
+
+            /**
+             * Predefined cubic Bezier function. See
+             * [ease-in](https://www.w3.org/TR/css-easing-1/#cubic-bezier-easing-functions)
+             * and @see [CubicBezier] about input values outside [0, 1])
+             */
+            @JvmField public val EASE_IN: Predefined = Predefined(2)
+
+            /**
+             * Predefined cubic Bezier function. See
+             * [ease-out](https://www.w3.org/TR/css-easing-1/#cubic-bezier-easing-functions)
+             * and @see [CubicBezier] about input values outside [0, 1])
+             */
+            @JvmField public val EASE_OUT: Predefined = Predefined(3)
+
+            /**
+             * Predefined cubic Bezier function. See
+             * [ease-in-out](https://www.w3.org/TR/css-easing-1/#cubic-bezier-easing-functions)
+             * and @see [CubicBezier] about input values outside [0, 1])
+             */
+            @JvmField public val EASE_IN_OUT: Predefined = Predefined(4)
+
+            /**
+             * Predefined step function with a jump-start at input progress value of 0. See
+             * [step start](https://www.w3.org/TR/css-easing-1/#step-easing-functions)
+             */
+            @JvmField public val STEP_START: Predefined = Predefined(5)
+
+            /**
+             * Predefined step function with a jump-end at input progress value of 1. See
+             * [step end](https://www.w3.org/TR/css-easing-1/#step-easing-functions)
+             */
+            @JvmField public val STEP_END: Predefined = Predefined(6)
+
+            private const val PREFIX = "EasingFunction.Predefined."
+        }
+    }
+
+    /**
+     * Parameters for a custom cubic Bezier easing function.
+     *
+     * A cubic Bezier is generally defined by four points, P0 - P3. In the case of the easing
+     * function, P0 is defined to be the point (0, 0), and P3 is defined to be the point (1, 1). The
+     * values of [x1] and [x2] are required to be in the range [0, 1]. This guarantees that the
+     * resulting curve is a function with respect to x and follows the CSS cubic Bezier
+     * specification:
+     * [https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function#cubic_b%C3%A9zier_easing_function](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function#cubic_b%C3%A9zier_easing_function)
+     *
+     * Valid parameters must have all finite values, and [x1] and [x2] must be in the interval
+     * [0, 1].
+     *
+     * Input x values that are outside the interval [0, 1] will be clamped, but output values will
+     * not. This is somewhat different from the w3c defined cubic Bezier that allows extrapolated
+     * values outside x in [0, 1] by following end-point tangents.
+     */
+    public class CubicBezier(
+        @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+        public val x1: Float,
+        public val y1: Float,
+        @FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true)
+        public val x2: Float,
+        public val y2: Float,
+    ) : EasingFunction() {
+        init {
+            require(x1.isFinite() && x2.isFinite() && y1.isFinite() && y2.isFinite()) {
+                "All parameters must be finite. x1 = $x1, x2 = $x2, y1 = $y1, y2 = $y2"
+            }
+            require(x1 in 0.0..1.0) { "x1 = $x1 is required to be in the range [0, 1]" }
+            require(x2 in 0.0..1.0) { "x2 = $x2 is required to be in the range [0, 1]" }
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is CubicBezier) {
+                return false
+            }
+            return x1 == other.x1 && x2 == other.x2 && y1 == other.y1 && y2 == other.y2
+        }
+
+        override fun hashCode(): Int {
+            var result = x1.hashCode()
+            result = 31 * result + x2.hashCode()
+            result = 31 * result + y1.hashCode()
+            result = 31 * result + y2.hashCode()
+            return result
+        }
+
+        override fun toString(): String =
+            "EasingFunction.CubicBezier(x1=$x1, y1=$y1, x2=$x2, y2=$y2)"
+
+        // Declared to make extension functions available.
+        public companion object
+    }
+
+    /**
+     * Parameters for a custom piecewise-linear easing function.
+     *
+     * A piecewise-linear function is defined by a sequence of points; the value of the function at
+     * an x-position equal to one of those points is equal to the y-position of that point, and the
+     * value of the function at an x-position between two points is equal to the linear
+     * interpolation between those points' y-positions. This easing function implicitly includes the
+     * points (0, 0) and (1, 1), so the `points` field below need only include any points between
+     * those. If [points] is empty, then this function is equivalent to the [Predefined.LINEAR]
+     * identity function.
+     *
+     * To be valid, all y-positions must be finite, and all x-positions must be in the range [0, 1]
+     * and must be monotonically non-decreasing. It is valid for multiple points to have the same
+     * x-position, in order to create a discontinuity in the function; in that case, the value of
+     * the function at exactly that x-position is equal to the y-position of the last of these
+     * points.
+     *
+     * If the input x-value is outside the interval [0, 1], the output will be extrapolated from the
+     * first/last line segment.
+     */
+    public class Linear(
+        // The [points] val below is a defensive copy of this parameter.
+        points: List
+    ) : EasingFunction() {
+        public val points: List = unmodifiableList(points.toList())
+
+        init {
+            for (point: ImmutableVec in points) {
+                require(point.x.isFinite() && point.y.isFinite()) {
+                    "All points must be finite. Got $point"
+                }
+                require(point.x in 0.0..1.0) {
+                    "point.x is required to be in the range [0, 1]. Got $point"
+                }
+            }
+            for ((a, b) in points.zipWithNext()) {
+                require(a.x <= b.x) { "Points must be sorted by x-value. Got $a before $b" }
+            }
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is Linear) {
+                return false
+            }
+            return points == other.points
+        }
+
+        override fun hashCode(): Int {
+            return points.hashCode()
+        }
+
+        override fun toString(): String = "EasingFunction.Linear(${points})"
+
+        // Declared to make extension functions available.
+        public companion object
+    }
+
+    /**
+     * Parameters for a custom step easing function.
+     *
+     * A step function is defined by the number of equal-sized steps into which the
+     * [0, 1) interval of input-x is split and the behavior at the extremes. When x < 0, the output will always be 0. When x >= 1, the output will always be 1. The output of the first and last steps is governed by the [StepPosition].
+     *
+     * @param stepCount The number of steps. Must always be greater than 0, and must be greater than
+     *   1 if [stepPosition] is [StepPosition.JUMP_NONE].
+     *
+     * The behavior and naming follows the CSS steps() specification at
+     * [https://www.w3.org/TR/css-easing-1/#step-easing-functions](https://www.w3.org/TR/css-easing-1/#step-easing-functions)
+     */
+    public class Steps(public val stepCount: Int, public val stepPosition: StepPosition) :
+        EasingFunction() {
+        init {
+            require(stepCount > 0) { "stepCount = $stepCount is required to be greater than 0." }
+            require(stepPosition != StepPosition.JUMP_NONE || stepCount > 1) {
+                "stepCount = $stepCount is required to be greater than 1 if stepPosition = JUMP_NONE."
+            }
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is Steps) {
+                return false
+            }
+            return stepCount == other.stepCount && stepPosition == other.stepPosition
+        }
+
+        override fun hashCode(): Int {
+            var result = stepCount.hashCode()
+            result = 31 * result + stepPosition.hashCode()
+            return result
+        }
+
+        override fun toString(): String =
+            "EasingFunction.Steps(stepCount=$stepCount, stepPosition=$stepPosition)"
+
+        // Declared to make extension functions available.
+        public companion object
+    }
+
+    /**
+     * Setting to determine the desired output value of the first and last step of
+     * [0, 1) for [EasingFunction.Steps].
+     */
+    public class StepPosition private constructor(@JvmField internal val value: Int) :
+        EasingFunction() {
+
+        public fun toSimpleString(): String =
+            when (value) {
+                0 -> "JUMP_END"
+                1 -> "JUMP_START"
+                2 -> "JUMP_BOTH"
+                3 -> "JUMP_NONE"
+                else -> "INVALID"
+            }
+
+        override fun toString(): String = PREFIX + toSimpleString()
+
+        override fun equals(other: Any?): Boolean {
+            if (other == null || other !is StepPosition) return false
+            return value == other.value
+        }
+
+        override fun hashCode(): Int = value.hashCode()
+
+        public companion object {
+            /**
+             * The step function "jumps" at the end of [0, 1): For x in [0, 1/step_count) => y = 0.
+             * For x in [1 - 1/step_count, 1) => y = 1 - 1/step_count.
+             */
+            @JvmField public val JUMP_END: StepPosition = StepPosition(0)
+            /**
+             * The step function "jumps" at the start of [0, 1): For x in [0, 1/step_count) => y =
+             * 1/step_count. For x in [1 - 1/step_count, 1) => y = 1.
+             */
+            @JvmField public val JUMP_START: StepPosition = StepPosition(1)
+            /**
+             * The step function "jumps" at both the start and the end: For x in [0, 1/step_count)
+             * => y = 1/(step_count + 1). For x in [1 - 1/step_count, 1) => y = 1 - 1/(step_count +
+             * 1).
+             */
+            @JvmField public val JUMP_BOTH: StepPosition = StepPosition(2)
+
+            /**
+             * The step function does not "jump" at either boundary: For x in [0, 1/step_count) => y
+             * = 0. For x in [1 - 1/step_count, 1) => y = 1.
+             */
+            @JvmField public val JUMP_NONE: StepPosition = StepPosition(3)
+            private const val PREFIX = "EasingFunction.StepPosition."
+        }
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ExperimentalInkCustomBrushApi.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ExperimentalInkCustomBrushApi.kt
new file mode 100644
index 0000000..c422f93
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/ExperimentalInkCustomBrushApi.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+/**
+ * Marks declarations that are are part of the **experimental** Ink brush customization API. These
+ * declarations may (or may not) be changed, deprecated, or removed in the near future, or the
+ * semantics of their behavior may change in some way that may break some code.
+ *
+ * You can opt in to using APIs in your code by marking your declaration with `@OptIn` passing the
+ * opt-in requirement annotation as its argument: `@OptIn(ExperimentalInkCustomBrushApi::class)`.
+ */
+@MustBeDocumented
+@Retention(value = AnnotationRetention.BINARY)
+@Target(
+    AnnotationTarget.CLASS,
+    AnnotationTarget.ANNOTATION_CLASS,
+    AnnotationTarget.PROPERTY,
+    AnnotationTarget.FIELD,
+    AnnotationTarget.LOCAL_VARIABLE,
+    AnnotationTarget.VALUE_PARAMETER,
+    AnnotationTarget.CONSTRUCTOR,
+    AnnotationTarget.FUNCTION,
+    AnnotationTarget.PROPERTY_GETTER,
+    AnnotationTarget.PROPERTY_SETTER,
+    AnnotationTarget.TYPEALIAS,
+)
+@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
+public annotation class ExperimentalInkCustomBrushApi
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/InputToolType.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/InputToolType.kt
new file mode 100644
index 0000000..90626ce
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/InputToolType.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import kotlin.jvm.JvmName
+import kotlin.jvm.JvmStatic
+
+/**
+ * The type of input tool used in producing [com.google.inputmethod.ink.strokes.StrokeInput], used
+ * by [BrushBehavior] to define when a behavior is applicable.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+
+// TODO: b/355248266 - @UsedByNative("stroke_input_jni_helper.cc") must go in Proguard config file
+// instead.
+public class InputToolType
+private constructor(
+    @JvmField
+    @field:RestrictTo(
+        RestrictTo.Scope.LIBRARY_GROUP
+    ) // NonPublicApi // TODO: b/355248266 - @UsedByNative("stroke_input_jni_helper.cc") must go in
+    // Proguard config file instead.
+    public val value: Int
+) {
+
+    private fun toSimpleString(): String =
+        when (this) {
+            UNKNOWN -> "UNKNOWN"
+            MOUSE -> "MOUSE"
+            TOUCH -> "TOUCH"
+            STYLUS -> "STYLUS"
+            else -> "INVALID"
+        }
+
+    public override fun toString(): String = PREFIX + this.toSimpleString()
+
+    public override fun equals(other: Any?): Boolean {
+        if (other == null || other !is InputToolType) return false
+        return value == other.value
+    }
+
+    public override fun hashCode(): Int = value.hashCode()
+
+    public companion object {
+        /**
+         * Get InputToolType by Int. Accessible internally for conversion to and from C++
+         * representations of ToolType in JNI code and in internal Kotlin code. The `internal`
+         * keyword obfuscates the function signature, hence the need for JvmName annotation.
+         */
+        @JvmStatic
+        @JvmName("from")
+        // TODO: b/355248266 - @UsedByNative("stroke_input_jni_helper.cc") must go in Proguard
+        // config file instead.
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public fun from(value: Int): InputToolType {
+            return when (value) {
+                UNKNOWN.value -> UNKNOWN
+                MOUSE.value -> MOUSE
+                TOUCH.value -> TOUCH
+                STYLUS.value -> STYLUS
+                else -> throw IllegalArgumentException("Invalid value: $value")
+            }
+        }
+
+        @JvmField public val UNKNOWN: InputToolType = InputToolType(0)
+        @JvmField public val MOUSE: InputToolType = InputToolType(1)
+        @JvmField public val TOUCH: InputToolType = InputToolType(2)
+        @JvmField public val STYLUS: InputToolType = InputToolType(3)
+        private const val PREFIX = "InputToolType."
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/StockBrushes.kt b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/StockBrushes.kt
new file mode 100644
index 0000000..9c9aec67
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidMain/kotlin/androidx/ink/brush/StockBrushes.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.annotation.RestrictTo
+import androidx.ink.geometry.Angle
+import kotlin.jvm.JvmStatic
+
+/**
+ * Provides a fixed set of stock [BrushFamily] objects that any app can use.
+ *
+ * The list of available stock brushes includes:
+ * - Marker: A simple, circular fixed-width brush.
+ * - Pressure Pen: A pressure- and speed-sensitive brush that is optimized for handwriting with a
+ *   stylus.
+ * - Highlighter: A chisel-tip brush that is intended for highlighting text in a document (when used
+ *   with a translucent brush color).
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
+@OptIn(ExperimentalInkCustomBrushApi::class)
+public object StockBrushes {
+    // Needed on both property and on getter for AndroidX build, but the Kotlin compiler doesn't
+    // like it on the getter so suppress its complaint.
+    @ExperimentalInkCustomBrushApi
+    @get:ExperimentalInkCustomBrushApi
+    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
+    @JvmStatic
+    public val predictionFadeOutBehavior: BrushBehavior =
+        BrushBehavior(
+            source = BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_MILLIS,
+            target = BrushBehavior.Target.OPACITY_MULTIPLIER,
+            sourceValueRangeLowerBound = 0F,
+            sourceValueRangeUpperBound = 24F,
+            targetModifierRangeLowerBound = 1F,
+            targetModifierRangeUpperBound = 0.3F,
+        )
+
+    /**
+     * Version 1 of the stock marker. This brush spec will not meaningfully change in future
+     * releases, even as this property is marked [@Deprecated] and a new version is added.
+     */
+    @JvmStatic
+    public val markerV1: BrushFamily =
+        BrushFamily(tip = BrushTip(behaviors = listOf(predictionFadeOutBehavior)))
+
+    /**
+     * The latest version of the stock marker brush. This brush spec may change in future releases.
+     */
+    @JvmStatic public val marker: BrushFamily = markerV1
+
+    /**
+     * Version 1 of the stock pressure pen. This brush spec will not meaningfully change in future
+     * releases, even as this property is marked [@Deprecated] and a new version is added.
+     */
+    @JvmStatic
+    public val pressurePenV1: BrushFamily =
+        BrushFamily(
+            tip =
+                BrushTip(
+                    behaviors =
+                        listOf(
+                            predictionFadeOutBehavior,
+                            BrushBehavior(
+                                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                                target = BrushBehavior.Target.SIZE_MULTIPLIER,
+                                sourceValueRangeLowerBound = 0f,
+                                sourceValueRangeUpperBound = 1f,
+                                targetModifierRangeLowerBound = 0.05f,
+                                targetModifierRangeUpperBound = 1f,
+                                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                                responseCurve = EasingFunction.Predefined.LINEAR,
+                                responseTimeMillis = 40L,
+                                enabledToolTypes = setOf(InputToolType.STYLUS),
+                            ),
+                        )
+                )
+        )
+
+    /**
+     * The latest version of the stock pressure pen. This brush spec may change in future releases.
+     */
+    @JvmStatic public val pressurePen: BrushFamily = pressurePenV1
+
+    /**
+     * Version 1 of the stock highlighter. This brush spec will not meaningfully change in future
+     * releases, even as this property is marked [@Deprecated] and a new version is added.
+     */
+    @JvmStatic
+    public val highlighterV1: BrushFamily =
+        BrushFamily(
+            tip =
+                BrushTip(
+                    scaleX = 0.05f,
+                    scaleY = 1f,
+                    cornerRounding = 0.11f,
+                    rotation = Angle.degreesToRadians(150f),
+                    behaviors = listOf(predictionFadeOutBehavior),
+                )
+        )
+
+    /**
+     * The latest version of the stock highlighter. This brush spec may change in future releases.
+     */
+    @JvmStatic public val highlighter: BrushFamily = highlighterV1
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushBehaviorTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushBehaviorTest.kt
new file mode 100644
index 0000000..b440efa
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushBehaviorTest.kt
@@ -0,0 +1,890 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import com.google.common.truth.Truth.assertThat
+import kotlin.IllegalArgumentException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class BrushBehaviorTest {
+
+    @Test
+    fun sourceConstants_areDistinct() {
+        val list =
+            listOf(
+                BrushBehavior.Source.CONSTANT_ZERO,
+                BrushBehavior.Source.NORMALIZED_PRESSURE,
+                BrushBehavior.Source.TILT_IN_RADIANS,
+                BrushBehavior.Source.TILT_X_IN_RADIANS,
+                BrushBehavior.Source.TILT_Y_IN_RADIANS,
+                BrushBehavior.Source.ORIENTATION_IN_RADIANS,
+                BrushBehavior.Source.ORIENTATION_ABOUT_ZERO_IN_RADIANS,
+                BrushBehavior.Source.SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND,
+                BrushBehavior.Source.VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND,
+                BrushBehavior.Source.VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND,
+                BrushBehavior.Source.DIRECTION_IN_RADIANS,
+                BrushBehavior.Source.DIRECTION_ABOUT_ZERO_IN_RADIANS,
+                BrushBehavior.Source.NORMALIZED_DIRECTION_X,
+                BrushBehavior.Source.NORMALIZED_DIRECTION_Y,
+                BrushBehavior.Source.DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Source.TIME_OF_INPUT_IN_SECONDS,
+                BrushBehavior.Source.TIME_OF_INPUT_IN_MILLIS,
+                BrushBehavior.Source.PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_SECONDS,
+                BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_MILLIS,
+                BrushBehavior.Source.DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Source.TIME_SINCE_INPUT_IN_SECONDS,
+                BrushBehavior.Source.TIME_SINCE_INPUT_IN_MILLIS,
+                BrushBehavior.Source.ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED,
+                BrushBehavior.Source.ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED,
+                BrushBehavior.Source.ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED,
+                BrushBehavior.Source
+                    .ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED,
+                BrushBehavior.Source
+                    .ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED,
+                BrushBehavior.Source.INPUT_SPEED_IN_CENTIMETERS_PER_SECOND,
+                BrushBehavior.Source.INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND,
+                BrushBehavior.Source.INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND,
+                BrushBehavior.Source.INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS,
+                BrushBehavior.Source.PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS,
+                BrushBehavior.Source.INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED,
+                BrushBehavior.Source.INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED,
+                BrushBehavior.Source.INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED,
+                BrushBehavior.Source.INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED,
+                BrushBehavior.Source.INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED,
+            )
+        assertThat(list.toSet()).hasSize(list.size)
+    }
+
+    @Test
+    fun sourceHashCode_withIdenticalValues_match() {
+        assertThat(BrushBehavior.Source.NORMALIZED_PRESSURE.hashCode())
+            .isEqualTo(BrushBehavior.Source.NORMALIZED_PRESSURE.hashCode())
+
+        assertThat(BrushBehavior.Source.TILT_IN_RADIANS.hashCode())
+            .isNotEqualTo(BrushBehavior.Source.NORMALIZED_PRESSURE.hashCode())
+    }
+
+    @Test
+    fun sourceEquals_checksEqualityOfValues() {
+        assertThat(BrushBehavior.Source.NORMALIZED_PRESSURE)
+            .isEqualTo(BrushBehavior.Source.NORMALIZED_PRESSURE)
+
+        assertThat(BrushBehavior.Source.TILT_IN_RADIANS)
+            .isNotEqualTo(BrushBehavior.Source.NORMALIZED_PRESSURE)
+        assertThat(BrushBehavior.Source.TILT_IN_RADIANS).isNotEqualTo(null)
+    }
+
+    @Test
+    fun sourceToString_returnsCorrectString() {
+        assertThat(BrushBehavior.Source.CONSTANT_ZERO.toString())
+            .isEqualTo("BrushBehavior.Source.CONSTANT_ZERO")
+        assertThat(BrushBehavior.Source.NORMALIZED_PRESSURE.toString())
+            .isEqualTo("BrushBehavior.Source.NORMALIZED_PRESSURE")
+        assertThat(BrushBehavior.Source.TILT_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.TILT_IN_RADIANS")
+        assertThat(BrushBehavior.Source.TILT_X_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.TILT_X_IN_RADIANS")
+        assertThat(BrushBehavior.Source.TILT_Y_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.TILT_Y_IN_RADIANS")
+        assertThat(BrushBehavior.Source.ORIENTATION_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.ORIENTATION_IN_RADIANS")
+        assertThat(BrushBehavior.Source.ORIENTATION_ABOUT_ZERO_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.ORIENTATION_ABOUT_ZERO_IN_RADIANS")
+        assertThat(BrushBehavior.Source.SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.SPEED_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND")
+        assertThat(BrushBehavior.Source.VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.VELOCITY_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND")
+        assertThat(BrushBehavior.Source.VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.VELOCITY_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND")
+        assertThat(BrushBehavior.Source.DIRECTION_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.DIRECTION_IN_RADIANS")
+        assertThat(BrushBehavior.Source.DIRECTION_ABOUT_ZERO_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Source.DIRECTION_ABOUT_ZERO_IN_RADIANS")
+        assertThat(BrushBehavior.Source.NORMALIZED_DIRECTION_X.toString())
+            .isEqualTo("BrushBehavior.Source.NORMALIZED_DIRECTION_X")
+        assertThat(BrushBehavior.Source.NORMALIZED_DIRECTION_Y.toString())
+            .isEqualTo("BrushBehavior.Source.NORMALIZED_DIRECTION_Y")
+        assertThat(BrushBehavior.Source.DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE.toString())
+            .isEqualTo("BrushBehavior.Source.DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(BrushBehavior.Source.TIME_OF_INPUT_IN_SECONDS.toString())
+            .isEqualTo("BrushBehavior.Source.TIME_OF_INPUT_IN_SECONDS")
+        assertThat(BrushBehavior.Source.TIME_OF_INPUT_IN_MILLIS.toString())
+            .isEqualTo("BrushBehavior.Source.TIME_OF_INPUT_IN_MILLIS")
+        assertThat(
+                BrushBehavior.Source.PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.PREDICTED_DISTANCE_TRAVELED_IN_MULTIPLES_OF_BRUSH_SIZE"
+            )
+        assertThat(BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_SECONDS.toString())
+            .isEqualTo("BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_SECONDS")
+        assertThat(BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_MILLIS.toString())
+            .isEqualTo("BrushBehavior.Source.PREDICTED_TIME_ELAPSED_IN_MILLIS")
+        assertThat(BrushBehavior.Source.DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE.toString())
+            .isEqualTo("BrushBehavior.Source.DISTANCE_REMAINING_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(BrushBehavior.Source.TIME_SINCE_INPUT_IN_SECONDS.toString())
+            .isEqualTo("BrushBehavior.Source.TIME_SINCE_INPUT_IN_SECONDS")
+        assertThat(BrushBehavior.Source.TIME_SINCE_INPUT_IN_MILLIS.toString())
+            .isEqualTo("BrushBehavior.Source.TIME_SINCE_INPUT_IN_MILLIS")
+        assertThat(
+                BrushBehavior.Source.ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.ACCELERATION_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source.ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.ACCELERATION_X_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source.ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.ACCELERATION_Y_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source
+                    .ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.ACCELERATION_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source
+                    .ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.ACCELERATION_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE_PER_SECOND_SQUARED"
+            )
+        assertThat(BrushBehavior.Source.INPUT_SPEED_IN_CENTIMETERS_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.INPUT_SPEED_IN_CENTIMETERS_PER_SECOND")
+        assertThat(BrushBehavior.Source.INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.INPUT_VELOCITY_X_IN_CENTIMETERS_PER_SECOND")
+        assertThat(BrushBehavior.Source.INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND.toString())
+            .isEqualTo("BrushBehavior.Source.INPUT_VELOCITY_Y_IN_CENTIMETERS_PER_SECOND")
+        assertThat(BrushBehavior.Source.INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS.toString())
+            .isEqualTo("BrushBehavior.Source.INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS")
+        assertThat(BrushBehavior.Source.PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS.toString())
+            .isEqualTo("BrushBehavior.Source.PREDICTED_INPUT_DISTANCE_TRAVELED_IN_CENTIMETERS")
+        assertThat(
+                BrushBehavior.Source.INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED.toString()
+            )
+            .isEqualTo("BrushBehavior.Source.INPUT_ACCELERATION_IN_CENTIMETERS_PER_SECOND_SQUARED")
+        assertThat(
+                BrushBehavior.Source.INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.INPUT_ACCELERATION_X_IN_CENTIMETERS_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source.INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.INPUT_ACCELERATION_Y_IN_CENTIMETERS_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source.INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.INPUT_ACCELERATION_FORWARD_IN_CENTIMETERS_PER_SECOND_SQUARED"
+            )
+        assertThat(
+                BrushBehavior.Source.INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior.Source.INPUT_ACCELERATION_LATERAL_IN_CENTIMETERS_PER_SECOND_SQUARED"
+            )
+    }
+
+    @Test
+    fun targetConstants_areDistinct() {
+        val list =
+            listOf(
+                BrushBehavior.Target.WIDTH_MULTIPLIER,
+                BrushBehavior.Target.HEIGHT_MULTIPLIER,
+                BrushBehavior.Target.SIZE_MULTIPLIER,
+                BrushBehavior.Target.SLANT_OFFSET_IN_RADIANS,
+                BrushBehavior.Target.PINCH_OFFSET,
+                BrushBehavior.Target.ROTATION_OFFSET_IN_RADIANS,
+                BrushBehavior.Target.CORNER_ROUNDING_OFFSET,
+                BrushBehavior.Target.POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Target.POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Target.POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Target.POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE,
+                BrushBehavior.Target.HUE_OFFSET_IN_RADIANS,
+                BrushBehavior.Target.SATURATION_MULTIPLIER,
+                BrushBehavior.Target.LUMINOSITY,
+                BrushBehavior.Target.OPACITY_MULTIPLIER,
+            )
+        assertThat(list.toSet()).hasSize(list.size)
+    }
+
+    @Test
+    fun targetHashCode_withIdenticalValues_match() {
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER.hashCode())
+            .isEqualTo(BrushBehavior.Target.WIDTH_MULTIPLIER.hashCode())
+
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER.hashCode())
+            .isNotEqualTo(BrushBehavior.Target.HEIGHT_MULTIPLIER.hashCode())
+    }
+
+    @Test
+    fun targetEquals_checksEqualityOfValues() {
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER)
+            .isEqualTo(BrushBehavior.Target.WIDTH_MULTIPLIER)
+
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER)
+            .isNotEqualTo(BrushBehavior.Target.HEIGHT_MULTIPLIER)
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER).isNotEqualTo(null)
+    }
+
+    @Test
+    fun targetToString_returnsCorrectString() {
+        assertThat(BrushBehavior.Target.WIDTH_MULTIPLIER.toString())
+            .isEqualTo("BrushBehavior.Target.WIDTH_MULTIPLIER")
+        assertThat(BrushBehavior.Target.HEIGHT_MULTIPLIER.toString())
+            .isEqualTo("BrushBehavior.Target.HEIGHT_MULTIPLIER")
+        assertThat(BrushBehavior.Target.SIZE_MULTIPLIER.toString())
+            .isEqualTo("BrushBehavior.Target.SIZE_MULTIPLIER")
+        assertThat(BrushBehavior.Target.SLANT_OFFSET_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Target.SLANT_OFFSET_IN_RADIANS")
+        assertThat(BrushBehavior.Target.PINCH_OFFSET.toString())
+            .isEqualTo("BrushBehavior.Target.PINCH_OFFSET")
+        assertThat(BrushBehavior.Target.ROTATION_OFFSET_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Target.ROTATION_OFFSET_IN_RADIANS")
+        assertThat(BrushBehavior.Target.CORNER_ROUNDING_OFFSET.toString())
+            .isEqualTo("BrushBehavior.Target.CORNER_ROUNDING_OFFSET")
+        assertThat(BrushBehavior.Target.POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE.toString())
+            .isEqualTo("BrushBehavior.Target.POSITION_OFFSET_X_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(BrushBehavior.Target.POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE.toString())
+            .isEqualTo("BrushBehavior.Target.POSITION_OFFSET_Y_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(
+                BrushBehavior.Target.POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE.toString()
+            )
+            .isEqualTo("BrushBehavior.Target.POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(
+                BrushBehavior.Target.POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE.toString()
+            )
+            .isEqualTo("BrushBehavior.Target.POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE")
+        assertThat(BrushBehavior.Target.HUE_OFFSET_IN_RADIANS.toString())
+            .isEqualTo("BrushBehavior.Target.HUE_OFFSET_IN_RADIANS")
+        assertThat(BrushBehavior.Target.SATURATION_MULTIPLIER.toString())
+            .isEqualTo("BrushBehavior.Target.SATURATION_MULTIPLIER")
+        assertThat(BrushBehavior.Target.LUMINOSITY.toString())
+            .isEqualTo("BrushBehavior.Target.LUMINOSITY")
+        assertThat(BrushBehavior.Target.OPACITY_MULTIPLIER.toString())
+            .isEqualTo("BrushBehavior.Target.OPACITY_MULTIPLIER")
+    }
+
+    @Test
+    fun outOfRangeConstants_areDistinct() {
+        val list =
+            listOf(
+                BrushBehavior.OutOfRange.CLAMP,
+                BrushBehavior.OutOfRange.REPEAT,
+                BrushBehavior.OutOfRange.MIRROR,
+            )
+        assertThat(list.toSet()).hasSize(list.size)
+    }
+
+    @Test
+    fun outOfRangeHashCode_withIdenticalValues_match() {
+        assertThat(BrushBehavior.OutOfRange.CLAMP.hashCode())
+            .isEqualTo(BrushBehavior.OutOfRange.CLAMP.hashCode())
+
+        assertThat(BrushBehavior.OutOfRange.CLAMP.hashCode())
+            .isNotEqualTo(BrushBehavior.OutOfRange.REPEAT.hashCode())
+    }
+
+    @Test
+    fun outOfRangeEquals_checksEqualityOfValues() {
+        assertThat(BrushBehavior.OutOfRange.CLAMP).isEqualTo(BrushBehavior.OutOfRange.CLAMP)
+
+        assertThat(BrushBehavior.OutOfRange.CLAMP).isNotEqualTo(BrushBehavior.OutOfRange.REPEAT)
+        assertThat(BrushBehavior.OutOfRange.CLAMP).isNotEqualTo(null)
+    }
+
+    @Test
+    fun outOfRangeToString_returnsCorrectString() {
+        assertThat(BrushBehavior.OutOfRange.CLAMP.toString())
+            .isEqualTo("BrushBehavior.OutOfRange.CLAMP")
+        assertThat(BrushBehavior.OutOfRange.REPEAT.toString())
+            .isEqualTo("BrushBehavior.OutOfRange.REPEAT")
+        assertThat(BrushBehavior.OutOfRange.MIRROR.toString())
+            .isEqualTo("BrushBehavior.OutOfRange.MIRROR")
+    }
+
+    @Test
+    fun optionalInputPropertyConstants_areDistinct() {
+        val list =
+            listOf(
+                BrushBehavior.OptionalInputProperty.PRESSURE,
+                BrushBehavior.OptionalInputProperty.TILT,
+                BrushBehavior.OptionalInputProperty.ORIENTATION,
+                BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+            )
+        assertThat(list.toSet()).hasSize(list.size)
+    }
+
+    @Test
+    fun optionalInputPropertyHashCode_withIdenticalValues_match() {
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE.hashCode())
+            .isEqualTo(BrushBehavior.OptionalInputProperty.PRESSURE.hashCode())
+
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE.hashCode())
+            .isNotEqualTo(BrushBehavior.OptionalInputProperty.TILT.hashCode())
+    }
+
+    @Test
+    fun optionalInputPropertyEquals_checksEqualityOfValues() {
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE)
+            .isEqualTo(BrushBehavior.OptionalInputProperty.PRESSURE)
+
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE)
+            .isNotEqualTo(BrushBehavior.OptionalInputProperty.TILT)
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE).isNotEqualTo(null)
+    }
+
+    @Test
+    fun optionalInputPropertyToString_returnsCorrectString() {
+        assertThat(BrushBehavior.OptionalInputProperty.PRESSURE.toString())
+            .isEqualTo("BrushBehavior.OptionalInputProperty.PRESSURE")
+        assertThat(BrushBehavior.OptionalInputProperty.TILT.toString())
+            .isEqualTo("BrushBehavior.OptionalInputProperty.TILT")
+        assertThat(BrushBehavior.OptionalInputProperty.ORIENTATION.toString())
+            .isEqualTo("BrushBehavior.OptionalInputProperty.ORIENTATION")
+        assertThat(BrushBehavior.OptionalInputProperty.TILT_X_AND_Y.toString())
+            .isEqualTo("BrushBehavior.OptionalInputProperty.TILT_X_AND_Y")
+    }
+
+    @Test
+    fun brushBehaviorConstructor_withInvalidArguments_throws() {
+        // sourceValueRangeLowerBound not finite
+        val sourceValueRangeLowerBoundError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = Float.NaN, // Not finite.
+                    sourceValueRangeUpperBound = 1.0f,
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(sourceValueRangeLowerBoundError.message).contains("source")
+        assertThat(sourceValueRangeLowerBoundError.message).contains("finite")
+
+        // sourceValueRangeUpperBound not finite
+        val sourceValueRangeUpperBoundError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 1.0f,
+                    sourceValueRangeUpperBound = Float.NaN, // Not finite.
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(sourceValueRangeUpperBoundError.message).contains("source")
+        assertThat(sourceValueRangeUpperBoundError.message).contains("finite")
+
+        // sourceValueRangeUpperBound == sourceValueRangeUpperBound
+        val sourceValueRangeError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.5f, // same as upper bound.
+                    sourceValueRangeUpperBound = 0.5f, // same as lower bound.
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(sourceValueRangeError.message).contains("source")
+        assertThat(sourceValueRangeError.message).contains("distinct")
+
+        // targetModifierRangeLowerBound not finite
+        val targetModifierRangeLowerBoundError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = Float.NaN, // Not finite.
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(targetModifierRangeLowerBoundError.message).contains("target")
+        assertThat(targetModifierRangeLowerBoundError.message).contains("finite")
+
+        // targetModifierRangeUpperBound not finite
+        val targetModifierRangeUpperBoundError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = Float.NaN, // Not finite.
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(targetModifierRangeUpperBoundError.message).contains("target")
+        assertThat(targetModifierRangeUpperBoundError.message).contains("finite")
+
+        // responseTimeMillis less than 0L
+        val responseTimeMillisError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = -1L, // Less than 0.
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                )
+            }
+        assertThat(responseTimeMillisError.message).contains("response_time")
+        assertThat(responseTimeMillisError.message).contains("non-negative")
+
+        // enabledToolType contains empty set.
+        val enabledToolTypeError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(),
+                )
+            }
+        assertThat(enabledToolTypeError.message).contains("enabled_tool_types")
+        assertThat(enabledToolTypeError.message).contains("at least one")
+
+        // source and outOfRangeBehavior combination is invalid (TIME_SINCE_INPUT must use CLAMP)
+        val sourceOutOfRangeBehaviorError =
+            assertFailsWith {
+                BrushBehavior(
+                    source = BrushBehavior.Source.TIME_SINCE_INPUT_IN_SECONDS,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = 1.0f,
+                    targetModifierRangeUpperBound = 1.75f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.REPEAT,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 1L,
+                    enabledToolTypes = setOf(),
+                )
+            }
+        assertThat(sourceOutOfRangeBehaviorError.message).contains("TimeSince")
+        assertThat(sourceOutOfRangeBehaviorError.message).contains("kClamp")
+    }
+
+    @Test
+    fun brushBehaviorCopy_withArguments_createsCopyWithChanges() {
+        val behavior1 =
+            BrushBehavior(
+                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                sourceValueRangeLowerBound = 0.2f,
+                sourceValueRangeUpperBound = .8f,
+                targetModifierRangeLowerBound = 1.1f,
+                targetModifierRangeUpperBound = 1.7f,
+                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                responseTimeMillis = 1L,
+                enabledToolTypes = setOf(InputToolType.STYLUS),
+                isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+            )
+        assertThat(behavior1.copy(responseTimeMillis = 3L))
+            .isEqualTo(
+                BrushBehavior(
+                    source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                    target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                    sourceValueRangeLowerBound = 0.2f,
+                    sourceValueRangeUpperBound = .8f,
+                    targetModifierRangeLowerBound = 1.1f,
+                    targetModifierRangeUpperBound = 1.7f,
+                    sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                    responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                    responseTimeMillis = 3L,
+                    enabledToolTypes = setOf(InputToolType.STYLUS),
+                    isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+                )
+            )
+    }
+
+    @Test
+    fun brushBehaviorCopy_createsCopy() {
+        val behavior1 =
+            BrushBehavior(
+                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                sourceValueRangeLowerBound = 0.2f,
+                sourceValueRangeUpperBound = .8f,
+                targetModifierRangeLowerBound = 1.1f,
+                targetModifierRangeUpperBound = 1.7f,
+                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                responseTimeMillis = 1L,
+                enabledToolTypes = setOf(InputToolType.STYLUS),
+                isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+            )
+        val behavior2 = behavior1.copy()
+        assertThat(behavior2).isEqualTo(behavior1)
+        assertThat(behavior2).isNotSameInstanceAs(behavior1)
+    }
+
+    @Test
+    fun brushBehaviorToString_returnsReasonableString() {
+        assertThat(
+                BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                    .toString()
+            )
+            .isEqualTo(
+                "BrushBehavior(source=BrushBehavior.Source.NORMALIZED_PRESSURE, " +
+                    "target=BrushBehavior.Target.WIDTH_MULTIPLIER, " +
+                    "sourceOutOfRangeBehavior=BrushBehavior.OutOfRange.CLAMP, " +
+                    "sourceValueRangeLowerBound=0.0, sourceValueRangeUpperBound=1.0, " +
+                    "targetModifierRangeLowerBound=1.0, targetModifierRangeUpperBound=1.75, " +
+                    "responseCurve=EasingFunction.Predefined.EASE_IN_OUT, responseTimeMillis=1, " +
+                    "enabledToolTypes=[InputToolType.STYLUS], isFallbackFor=null)"
+            )
+    }
+
+    @Test
+    fun brushBehaviorEquals_withIdenticalValues_returnsTrue() {
+        val original =
+            BrushBehavior(
+                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                sourceValueRangeLowerBound = 0.0f,
+                sourceValueRangeUpperBound = 1.0f,
+                targetModifierRangeLowerBound = 1.0f,
+                targetModifierRangeUpperBound = 1.75f,
+                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                responseTimeMillis = 1L,
+                enabledToolTypes = setOf(InputToolType.STYLUS),
+            )
+
+        val exact =
+            BrushBehavior(
+                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                sourceValueRangeLowerBound = 0.0f,
+                sourceValueRangeUpperBound = 1.0f,
+                targetModifierRangeLowerBound = 1.0f,
+                targetModifierRangeUpperBound = 1.75f,
+                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                responseTimeMillis = 1L,
+                enabledToolTypes = setOf(InputToolType.STYLUS),
+            )
+
+        assertThat(original.equals(exact)).isTrue()
+    }
+
+    @Test
+    fun brushBehaviorEquals_withDifferentValues_returnsFalse() {
+        val original =
+            BrushBehavior(
+                source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                sourceValueRangeLowerBound = 0.0f,
+                sourceValueRangeUpperBound = 1.0f,
+                targetModifierRangeLowerBound = 1.0f,
+                targetModifierRangeUpperBound = 1.75f,
+                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                responseTimeMillis = 1L,
+                enabledToolTypes = setOf(InputToolType.STYLUS),
+            )
+
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.TILT_IN_RADIANS, // different
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.HEIGHT_MULTIPLIER, // different
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.REPEAT, // different
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.3f, // different
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 0.8f, // different
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.56f, // different
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.99f, // different
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.LINEAR, // different
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 35L, // different
+                        enabledToolTypes = setOf(InputToolType.STYLUS),
+                    )
+                )
+            )
+            .isFalse()
+        assertThat(
+                original.equals(
+                    BrushBehavior(
+                        source = BrushBehavior.Source.NORMALIZED_PRESSURE,
+                        target = BrushBehavior.Target.WIDTH_MULTIPLIER,
+                        sourceValueRangeLowerBound = 0.0f,
+                        sourceValueRangeUpperBound = 1.0f,
+                        targetModifierRangeLowerBound = 1.0f,
+                        targetModifierRangeUpperBound = 1.75f,
+                        sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.CLAMP,
+                        responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                        responseTimeMillis = 1L,
+                        enabledToolTypes = setOf(InputToolType.TOUCH), // different
+                    )
+                )
+            )
+            .isFalse()
+    }
+
+    /**
+     * Creates an expected C++ StepFunction BrushBehavior and returns true if every property of the
+     * Kotlin BrushBehavior's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushBehavior.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeStepBehavior(
+        nativePointerToActualBrushBehavior: Long
+    ): Boolean
+
+    /**
+     * Creates an expected C++ PredefinedFunction BrushBehavior and returns true if every property
+     * of the Kotlin BrushBehavior's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushBehavior.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativePredefinedBehavior(
+        nativePointerToActualBrushBehavior: Long
+    ): Boolean
+
+    /**
+     * Creates an expected C++ CubicBezier BrushBehavior and returns true if every property of the
+     * Kotlin BrushBehavior's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushBehavior.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeCubicBezierBehavior(
+        nativePointerToActualBrushBehavior: Long
+    ): Boolean
+
+    /**
+     * Creates an expected C++ Linear BrushBehavior and returns true if every property of the Kotlin
+     * BrushBehavior's JNI-created C++ counterpart is equivalent to the expected C++ BrushBehavior.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeLinearBehavior(
+        nativePointerToActualBrushBehavior: Long
+    ): Boolean
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushCoatTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushCoatTest.kt
new file mode 100644
index 0000000..a3504a3
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushCoatTest.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class BrushCoatTest {
+    @Test
+    fun constructor_withValidArguments_returnsABrushCoat() {
+        assertThat(BrushCoat(customTip, customPaint)).isNotNull()
+    }
+
+    @Test
+    fun constructor_withDefaultArguments_returnsABrushCoat() {
+        assertThat(BrushCoat(BrushTip(), BrushPaint())).isNotNull()
+    }
+
+    @Test
+    fun hashCode_withIdenticalValues_matches() {
+        assertThat(newCustomBrushCoat().hashCode()).isEqualTo(newCustomBrushCoat().hashCode())
+    }
+
+    @Test
+    fun equals_comparesValues() {
+        val brushCoat = BrushCoat(customTip, customPaint)
+        val differentTip = BrushTip()
+        val differentPaint = BrushPaint()
+
+        // same values are equal.
+        assertThat(brushCoat).isEqualTo(BrushCoat(customTip, customPaint))
+
+        // different values are not equal.
+        assertThat(brushCoat).isNotEqualTo(null)
+        assertThat(brushCoat).isNotEqualTo(Any())
+        assertThat(brushCoat).isNotEqualTo(brushCoat.copy(tip = differentTip))
+        assertThat(brushCoat).isNotEqualTo(brushCoat.copy(paint = differentPaint))
+    }
+
+    @Test
+    fun toString_returnsExpectedValues() {
+        assertThat(BrushCoat().toString())
+            .isEqualTo(
+                "BrushCoat(tips=[BrushTip(scale=(1.0, 1.0), " +
+                    "cornerRounding=1.0, slant=0.0, pinch=0.0, rotation=0.0, opacityMultiplier=1.0, " +
+                    "particleGapDistanceScale=0.0, particleGapDurationMillis=0, behaviors=[])], " +
+                    "paint=BrushPaint(textureLayers=[]))"
+            )
+    }
+
+    @Test
+    fun copy_whenSameContents_returnsSameInstance() {
+        val customCoat = BrushCoat(customTip, customPaint)
+
+        // A pure copy returns `this`.
+        val copy = customCoat.copy()
+        assertThat(copy).isSameInstanceAs(customCoat)
+    }
+
+    @Test
+    fun copy_withArguments_createsCopyWithChanges() {
+        val brushCoat = BrushCoat(customTip, customPaint)
+        val differentTip = BrushTip()
+        val differentPaint = BrushPaint()
+
+        assertThat(brushCoat.copy(tip = differentTip))
+            .isEqualTo(BrushCoat(differentTip, customPaint))
+        assertThat(brushCoat.copy(paint = differentPaint))
+            .isEqualTo(BrushCoat(customTip, differentPaint))
+    }
+
+    @Test
+    fun builder_createsExpectedBrushCoat() {
+        val coat = BrushCoat.Builder().setTip(customTip).setPaint(customPaint).build()
+        assertThat(coat).isEqualTo(BrushCoat(customTip, customPaint))
+    }
+
+    /**
+     * Creates an expected C++ BrushCoat with defaults and returns true if every property of the
+     * Kotlin BrushCoat's JNI-created C++ counterpart is equivalent to the expected C++ BrushCoat.
+     */
+    private external fun matchesDefaultCoat(
+        brushCoatNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /**
+     * Creates an expected C++ BrushCoat with custom values and returns true if every property of
+     * the Kotlin BrushCoat's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushCoat.
+     */
+    private external fun matchesMultiBehaviorTipCoat(
+        brushCoatNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /** Brush behavior with every field different from default values. */
+    private val customBehavior =
+        BrushBehavior(
+            source = BrushBehavior.Source.TILT_IN_RADIANS,
+            target = BrushBehavior.Target.HEIGHT_MULTIPLIER,
+            sourceValueRangeLowerBound = 0.2f,
+            sourceValueRangeUpperBound = .8f,
+            targetModifierRangeLowerBound = 1.1f,
+            targetModifierRangeUpperBound = 1.7f,
+            sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.MIRROR,
+            responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+            responseTimeMillis = 1L,
+            enabledToolTypes = setOf(InputToolType.STYLUS),
+            isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+        )
+
+    /** Brush tip with every field different from default values and non-empty behaviors. */
+    private val customTip =
+        BrushTip(
+            scaleX = 0.1f,
+            scaleY = 0.2f,
+            cornerRounding = 0.3f,
+            slant = 0.4f,
+            pinch = 0.5f,
+            rotation = 0.6f,
+            opacityMultiplier = 0.7f,
+            particleGapDistanceScale = 0.8f,
+            particleGapDurationMillis = 9L,
+            listOf(customBehavior),
+        )
+
+    /**
+     * Brush Paint with every field different from default values, including non-empty texture
+     * layers.
+     */
+    private val customPaint =
+        BrushPaint(
+            listOf(
+                BrushPaint.TextureLayer(
+                    colorTextureUri = "ink://ink/texture:test-one",
+                    sizeX = 123.45F,
+                    sizeY = 678.90F,
+                    offsetX = 0.123f,
+                    offsetY = 0.678f,
+                    rotation = 0.1f,
+                    opacity = 0.123f,
+                    BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                    BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                    BrushPaint.TextureMapping.TILING,
+                ),
+                BrushPaint.TextureLayer(
+                    colorTextureUri = "ink://ink/texture:test-two",
+                    sizeX = 256F,
+                    sizeY = 256F,
+                    offsetX = 0.456f,
+                    offsetY = 0.567f,
+                    rotation = 0.2f,
+                    opacity = 0.987f,
+                    BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                    BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                    BrushPaint.TextureMapping.TILING,
+                ),
+            )
+        )
+
+    /** Brush Coat with every field different from default values. */
+    private fun newCustomBrushCoat(): BrushCoat = BrushCoat(customTip, customPaint)
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushFamilyTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushFamilyTest.kt
new file mode 100644
index 0000000..a9197d5
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushFamilyTest.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class BrushFamilyTest {
+    @Test
+    fun constructor_withValidArguments_returnsABrushFamily() {
+        assertThat(BrushFamily(customTip, customPaint, customUri)).isNotNull()
+    }
+
+    @Test
+    fun constructor_withDefaultArguments_returnsABrushFamily() {
+        assertThat(BrushFamily(BrushTip(), BrushPaint(), uri = null)).isNotNull()
+        assertThat(BrushFamily(BrushTip(), BrushPaint(), uri = "")).isNotNull()
+    }
+
+    @Test
+    fun constructor_withBadUri_throws() {
+        assertFailsWith { BrushFamily(customTip, customPaint, "baduri") }
+    }
+
+    @Test
+    fun hashCode_withIdenticalValues_matches() {
+        assertThat(newCustomBrushFamily().hashCode()).isEqualTo(newCustomBrushFamily().hashCode())
+    }
+
+    @Test
+    fun equals_comparesValues() {
+        val brushFamily = BrushFamily(customTip, customPaint, customUri)
+        val differentCoat = BrushCoat(BrushTip(), BrushPaint())
+        val differentUri = null
+
+        // same values are equal.
+        assertThat(brushFamily).isEqualTo(BrushFamily(customTip, customPaint, customUri))
+
+        // different values are not equal.
+        assertThat(brushFamily).isNotEqualTo(null)
+        assertThat(brushFamily).isNotEqualTo(Any())
+        assertThat(brushFamily).isNotEqualTo(brushFamily.copy(coat = differentCoat))
+        assertThat(brushFamily).isNotEqualTo(brushFamily.copy(uri = differentUri))
+    }
+
+    @Test
+    fun toString_returnsExpectedValues() {
+        assertThat(BrushFamily().toString())
+            .isEqualTo(
+                "BrushFamily(coats=[BrushCoat(tips=[BrushTip(scale=(1.0, 1.0), " +
+                    "cornerRounding=1.0, slant=0.0, pinch=0.0, rotation=0.0, opacityMultiplier=1.0, " +
+                    "particleGapDistanceScale=0.0, particleGapDurationMillis=0, " +
+                    "behaviors=[])], paint=BrushPaint(textureLayers=[]))], uri=null)"
+            )
+    }
+
+    @Test
+    fun copy_whenSameContents_returnsSameInstance() {
+        val customFamily = BrushFamily(customTip, customPaint, customUri)
+
+        // A pure copy returns `this`.
+        val copy = customFamily.copy()
+        assertThat(copy).isSameInstanceAs(customFamily)
+    }
+
+    @Test
+    fun copy_withArguments_createsCopyWithChanges() {
+        val brushFamily = BrushFamily(customTip, customPaint, customUri)
+        val differentCoats = listOf(BrushCoat(BrushTip(), BrushPaint()))
+        val differentUri = null
+
+        assertThat(brushFamily.copy(coats = differentCoats))
+            .isEqualTo(BrushFamily(differentCoats, customUri))
+        assertThat(brushFamily.copy(uri = differentUri))
+            .isEqualTo(BrushFamily(customTip, customPaint, differentUri))
+    }
+
+    @Test
+    fun builder_createsExpectedBrushFamily() {
+        val family = BrushFamily.Builder().setCoat(customTip, customPaint).setUri(customUri).build()
+        assertThat(family).isEqualTo(BrushFamily(customTip, customPaint, customUri))
+    }
+
+    /**
+     * Creates an expected C++ BrushFamily with defaults and returns true if every property of the
+     * Kotlin BrushFamily's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushFamily.
+     */
+    private external fun matchesDefaultFamily(
+        brushFamilyNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /**
+     * Creates an expected C++ BrushFamily with custom values and returns true if every property of
+     * the Kotlin BrushFamily's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushFamily.
+     */
+    private external fun matchesMultiBehaviorTipFamily(
+        brushFamilyNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    private val customUri = "/brush-family:inkpen:1"
+
+    /** Brush behavior with every field different from default values. */
+    private val customBehavior =
+        BrushBehavior(
+            source = BrushBehavior.Source.TILT_IN_RADIANS,
+            target = BrushBehavior.Target.HEIGHT_MULTIPLIER,
+            sourceValueRangeLowerBound = 0.2f,
+            sourceValueRangeUpperBound = .8f,
+            targetModifierRangeLowerBound = 1.1f,
+            targetModifierRangeUpperBound = 1.7f,
+            sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.MIRROR,
+            responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+            responseTimeMillis = 1L,
+            enabledToolTypes = setOf(InputToolType.STYLUS),
+            isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+        )
+
+    /** Brush tip with every field different from default values and non-empty behaviors. */
+    private val customTip =
+        BrushTip(
+            scaleX = 0.1f,
+            scaleY = 0.2f,
+            cornerRounding = 0.3f,
+            slant = 0.4f,
+            pinch = 0.5f,
+            rotation = 0.6f,
+            opacityMultiplier = 0.7f,
+            particleGapDistanceScale = 0.8f,
+            particleGapDurationMillis = 9L,
+            listOf(customBehavior),
+        )
+
+    /**
+     * Brush Paint with every field different from default values, including non-empty texture
+     * layers.
+     */
+    private val customPaint =
+        BrushPaint(
+            listOf(
+                BrushPaint.TextureLayer(
+                    colorTextureUri = "ink://ink/texture:test-one",
+                    sizeX = 123.45F,
+                    sizeY = 678.90F,
+                    offsetX = 0.123f,
+                    offsetY = 0.678f,
+                    rotation = 0.1f,
+                    opacity = 0.123f,
+                    BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                    BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                    BrushPaint.TextureMapping.TILING,
+                ),
+                BrushPaint.TextureLayer(
+                    colorTextureUri = "ink://ink/texture:test-two",
+                    sizeX = 256F,
+                    sizeY = 256F,
+                    offsetX = 0.456f,
+                    offsetY = 0.567f,
+                    rotation = 0.2f,
+                    opacity = 0.987f,
+                    BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                    BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                    BrushPaint.TextureMapping.TILING,
+                ),
+            )
+        )
+
+    /** Brush Family with every field different from default values. */
+    private fun newCustomBrushFamily(): BrushFamily = BrushFamily(customTip, customPaint, customUri)
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushPaintTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushPaintTest.kt
new file mode 100644
index 0000000..1982d5f
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushPaintTest.kt
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.ink.geometry.Angle
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class BrushPaintTest {
+
+    // region BrushPaint class tests
+    @Test
+    fun constructor_withValidArguments_returnsABrushPaint() {
+        assertThat(
+                BrushPaint(
+                    listOf(
+                        BrushPaint.TextureLayer(
+                            colorTextureUri = makeTestTextureUri(1),
+                            sizeX = 123.45F,
+                            sizeY = 678.90F,
+                            offsetX = 0.1f,
+                            offsetY = 0.2f,
+                            rotation = Angle.QUARTER_TURN_RADIANS,
+                            opacity = 0.3f,
+                            BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                            BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                            BrushPaint.TextureMapping.TILING,
+                        ),
+                        BrushPaint.TextureLayer(
+                            colorTextureUri = makeTestTextureUri(2),
+                            sizeX = 256F,
+                            sizeY = 256F,
+                            offsetX = 0.8f,
+                            offsetY = 0.9f,
+                            rotation = Angle.HALF_TURN_RADIANS,
+                            opacity = 0.7f,
+                            BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+                            BrushPaint.TextureOrigin.FIRST_STROKE_INPUT,
+                            BrushPaint.TextureMapping.TILING,
+                        ),
+                    )
+                )
+            )
+            .isNotNull()
+    }
+
+    @Test
+    fun constructor_withDefaultArguments_returnsABrushPaint() {
+        assertThat(BrushPaint()).isNotNull()
+    }
+
+    @Test
+    fun hashCode_withIdenticalValues_matches() {
+        assertThat(BrushPaint(listOf(makeTestTextureLayer())).hashCode())
+            .isEqualTo(BrushPaint(listOf(makeTestTextureLayer())).hashCode())
+    }
+
+    @Test
+    fun equals_comparesValues() {
+        val customPaint = makeTestPaint()
+        val defaultPaint = BrushPaint()
+        // same values are equal.
+        assertThat(customPaint).isEqualTo(makeTestPaint())
+
+        // different values are not equal.
+        assertThat(customPaint).isNotEqualTo(null)
+        assertThat(customPaint).isNotEqualTo(Any())
+        assertThat(customPaint).isNotEqualTo(defaultPaint)
+    }
+
+    @Test
+    fun toString_returnsExpectedValues() {
+        val string = makeTestPaint().toString()
+        assertThat(string).contains("BrushPaint")
+        assertThat(string).contains("textureLayers")
+    }
+
+    // endregion
+
+    // region TextureLayer class tests
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun textureLayerConstructor_withInvalidSizes_throwsIllegalArgumentException() {
+        val fakeValidUri = makeTestTextureUri()
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, -32F, 64F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 32F, -64F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, -32F, -64F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 0F, 128F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 128F, 0F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, Float.NaN, 128F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 128F, Float.NaN)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, Float.POSITIVE_INFINITY, 128F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 128F, Float.POSITIVE_INFINITY)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, Float.NEGATIVE_INFINITY, 128F)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, 128F, Float.NEGATIVE_INFINITY)
+        }
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun textureLayerConstructor_withInvalidOffsetX_throwsIllegalArgumentException() {
+        val fakeValidUri = makeTestTextureUri()
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetX = Float.NaN)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetX = -0.001f)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetX = 1.001f)
+        }
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun textureLayerConstructor_withInvalidOffsetY_throwsIllegalArgumentException() {
+        val fakeValidUri = makeTestTextureUri()
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetY = Float.NaN)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetY = -0.001f)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, offsetY = 1.001f)
+        }
+    }
+
+    @Test
+    fun textureLayerConstructor_withInvalidRotation_throwsIllegalArgumentException() {
+        val fakeValidUri = makeTestTextureUri()
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, rotation = Float.NaN)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(
+                fakeValidUri,
+                sizeX = 1f,
+                sizeY = 1f,
+                rotation = Float.POSITIVE_INFINITY,
+            )
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(
+                fakeValidUri,
+                sizeX = 1f,
+                sizeY = 1f,
+                rotation = Float.NEGATIVE_INFINITY,
+            )
+        }
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun textureLayerConstructor_withInvalidOpacity_throwsIllegalArgumentException() {
+        val fakeValidUri = makeTestTextureUri()
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, opacity = Float.NaN)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, opacity = -0.001f)
+        }
+        assertFailsWith {
+            BrushPaint.TextureLayer(fakeValidUri, sizeX = 1f, sizeY = 1f, opacity = 1.001f)
+        }
+    }
+
+    @Test
+    fun textureLayerHashCode_withIdenticalValues_matches() {
+        assertThat(makeTestTextureLayer().hashCode()).isEqualTo(makeTestTextureLayer().hashCode())
+    }
+
+    @Test
+    fun textureLayerEquals_checksEqualityOfValues() {
+        val layer =
+            BrushPaint.TextureLayer(
+                colorTextureUri = makeTestTextureUri(),
+                sizeX = 128F,
+                sizeY = 128F,
+                offsetX = 0.1f,
+                offsetY = 0.2f,
+                rotation = Angle.QUARTER_TURN_RADIANS,
+                opacity = 0.3f,
+                BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+                BrushPaint.TextureOrigin.LAST_STROKE_INPUT,
+                BrushPaint.TextureMapping.WINDING,
+                BrushPaint.BlendMode.SRC_IN,
+            )
+
+        // same values.
+        assertThat(layer)
+            .isEqualTo(
+                BrushPaint.TextureLayer(
+                    colorTextureUri = makeTestTextureUri(),
+                    sizeX = 128F,
+                    sizeY = 128F,
+                    offsetX = 0.1f,
+                    offsetY = 0.2f,
+                    rotation = Angle.QUARTER_TURN_RADIANS,
+                    opacity = 0.3f,
+                    BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+                    BrushPaint.TextureOrigin.LAST_STROKE_INPUT,
+                    BrushPaint.TextureMapping.WINDING,
+                    BrushPaint.BlendMode.SRC_IN,
+                )
+            )
+
+        // different values.
+        assertThat(layer).isNotEqualTo(null)
+        assertThat(layer).isNotEqualTo(Any())
+        assertThat(layer).isNotEqualTo(layer.copy(colorTextureUri = makeTestTextureUri(2)))
+        assertThat(layer).isNotEqualTo(layer.copy(sizeX = 999F))
+        assertThat(layer).isNotEqualTo(layer.copy(sizeY = 999F))
+        assertThat(layer).isNotEqualTo(layer.copy(offsetX = 0.999F))
+        assertThat(layer).isNotEqualTo(layer.copy(offsetY = 0.999F))
+        assertThat(layer).isNotEqualTo(layer.copy(rotation = Angle.HALF_TURN_RADIANS))
+        assertThat(layer).isNotEqualTo(layer.copy(opacity = 0.999f))
+        assertThat(layer)
+            .isNotEqualTo(layer.copy(sizeUnit = BrushPaint.TextureSizeUnit.STROKE_COORDINATES))
+        assertThat(layer)
+            .isNotEqualTo(layer.copy(origin = BrushPaint.TextureOrigin.FIRST_STROKE_INPUT))
+        assertThat(layer).isNotEqualTo(layer.copy(mapping = BrushPaint.TextureMapping.TILING))
+        assertThat(layer).isNotEqualTo(layer.copy(blendMode = BrushPaint.BlendMode.MODULATE))
+    }
+
+    @Test
+    fun textureLayerCopy_createsCopy() {
+        val layer = makeTestTextureLayer()
+        val copy = layer.copy()
+
+        // Pure copy returns `this`.
+        assertThat(copy).isSameInstanceAs(layer)
+    }
+
+    @Test
+    fun textureLayerCopy_withArguments_createsCopyWithChanges() {
+        val originalLayer =
+            BrushPaint.TextureLayer(
+                colorTextureUri = makeTestTextureUri(),
+                sizeX = 128F,
+                sizeY = 128F,
+                offsetX = 0.1f,
+                offsetY = 0.2f,
+                rotation = Angle.QUARTER_TURN_RADIANS,
+                opacity = 0.3f,
+                BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+                BrushPaint.TextureOrigin.FIRST_STROKE_INPUT,
+                BrushPaint.TextureMapping.WINDING,
+                BrushPaint.BlendMode.SRC_IN,
+            )
+        val changedSizeX = originalLayer.copy(sizeX = 999F)
+
+        // sizeX changed.
+        assertThat(changedSizeX).isNotEqualTo(originalLayer)
+        assertThat(changedSizeX.sizeX).isNotEqualTo(originalLayer.sizeX)
+
+        assertThat(changedSizeX)
+            .isEqualTo(
+                BrushPaint.TextureLayer(
+                    colorTextureUri = makeTestTextureUri(),
+                    sizeX = 999F, // Changed
+                    sizeY = 128F,
+                    offsetX = 0.1f,
+                    offsetY = 0.2f,
+                    rotation = Angle.QUARTER_TURN_RADIANS,
+                    opacity = 0.3f,
+                    BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+                    BrushPaint.TextureOrigin.FIRST_STROKE_INPUT,
+                    BrushPaint.TextureMapping.WINDING,
+                    BrushPaint.BlendMode.SRC_IN,
+                )
+            )
+    }
+
+    @Test
+    fun textureLayerToString_returnsExpectedValues() {
+        val string = makeTestTextureLayer().toString()
+        assertThat(string).contains("TextureLayer")
+        assertThat(string).contains("colorTextureUri")
+        assertThat(string).contains("size")
+        assertThat(string).contains("offset")
+        assertThat(string).contains("rotation")
+        assertThat(string).contains("opacity")
+        assertThat(string).contains("sizeUnit")
+        assertThat(string).contains("origin")
+        assertThat(string).contains("mapping")
+        assertThat(string).contains("blendMode")
+    }
+
+    // endregion
+
+    // region SizeUnit class tests
+    @Test
+    fun sizeUnitConstants_areDistinct() {
+        val set =
+            setOf(
+                BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+                BrushPaint.TextureSizeUnit.STROKE_SIZE,
+                BrushPaint.TextureSizeUnit.STROKE_COORDINATES,
+            )
+        assertThat(set).hasSize(3)
+    }
+
+    @Test
+    fun sizeUnitHashCode_withIdenticalValues_match() {
+        assertThat(BrushPaint.TextureSizeUnit.STROKE_COORDINATES.hashCode())
+            .isEqualTo(BrushPaint.TextureSizeUnit.STROKE_COORDINATES.hashCode())
+    }
+
+    @Test
+    fun sizeUnitEquals_checksEqualityOfValues() {
+        assertThat(BrushPaint.TextureSizeUnit.STROKE_COORDINATES)
+            .isEqualTo(BrushPaint.TextureSizeUnit.STROKE_COORDINATES)
+        assertThat(BrushPaint.TextureSizeUnit.STROKE_COORDINATES)
+            .isNotEqualTo(BrushPaint.TextureSizeUnit.BRUSH_SIZE)
+    }
+
+    @Test
+    fun sizeUnitToString_returnsCorrectString() {
+        assertThat(BrushPaint.TextureSizeUnit.BRUSH_SIZE.toString())
+            .isEqualTo("BrushPaint.TextureSizeUnit.BRUSH_SIZE")
+        assertThat(BrushPaint.TextureSizeUnit.STROKE_SIZE.toString())
+            .isEqualTo("BrushPaint.TextureSizeUnit.STROKE_SIZE")
+        assertThat(BrushPaint.TextureSizeUnit.STROKE_COORDINATES.toString())
+            .isEqualTo("BrushPaint.TextureSizeUnit.STROKE_COORDINATES")
+    }
+
+    // endregion
+
+    // region Origin class tests
+    @Test
+    fun originConstants_areDistint() {
+        val set =
+            setOf(
+                BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN,
+                BrushPaint.TextureOrigin.FIRST_STROKE_INPUT,
+                BrushPaint.TextureOrigin.LAST_STROKE_INPUT,
+            )
+        assertThat(set).hasSize(3)
+    }
+
+    @Test
+    fun originHashCode_withIdenticalValues_match() {
+        assertThat(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT.hashCode())
+            .isEqualTo(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT.hashCode())
+    }
+
+    @Test
+    fun originEquals_checksEqualityOfValues() {
+        assertThat(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT)
+            .isEqualTo(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT)
+        assertThat(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT)
+            .isNotEqualTo(BrushPaint.TextureOrigin.LAST_STROKE_INPUT)
+    }
+
+    @Test
+    fun originToString_returnsCorrectString() {
+        assertThat(BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN.toString())
+            .isEqualTo("BrushPaint.TextureOrigin.STROKE_SPACE_ORIGIN")
+        assertThat(BrushPaint.TextureOrigin.FIRST_STROKE_INPUT.toString())
+            .isEqualTo("BrushPaint.TextureOrigin.FIRST_STROKE_INPUT")
+        assertThat(BrushPaint.TextureOrigin.LAST_STROKE_INPUT.toString())
+            .isEqualTo("BrushPaint.TextureOrigin.LAST_STROKE_INPUT")
+    }
+
+    // endregion
+
+    // region Mapping class tests
+    @Test
+    fun mappingConstants_areDistint() {
+        val set = setOf(BrushPaint.TextureMapping.TILING, BrushPaint.TextureMapping.WINDING)
+        assertThat(set).hasSize(2)
+    }
+
+    @Test
+    fun mappingHashCode_withIdenticalValues_match() {
+        assertThat(BrushPaint.TextureMapping.TILING.hashCode())
+            .isEqualTo(BrushPaint.TextureMapping.TILING.hashCode())
+    }
+
+    @Test
+    fun mappingEquals_checksEqualityOfValues() {
+        assertThat(BrushPaint.TextureMapping.TILING).isEqualTo(BrushPaint.TextureMapping.TILING)
+        assertThat(BrushPaint.TextureMapping.TILING).isNotEqualTo(BrushPaint.TextureMapping.WINDING)
+    }
+
+    @Test
+    fun mappingToString_returnsCorrectString() {
+        assertThat(BrushPaint.TextureMapping.TILING.toString())
+            .isEqualTo("BrushPaint.TextureMapping.TILING")
+        assertThat(BrushPaint.TextureMapping.WINDING.toString())
+            .isEqualTo("BrushPaint.TextureMapping.WINDING")
+    }
+
+    // endregion
+
+    // region BlendMode class tests
+    @Test
+    fun textureBlendModeConstants_areDistinct() {
+        val set =
+            setOf(
+                BrushPaint.BlendMode.MODULATE,
+                BrushPaint.BlendMode.DST_IN,
+                BrushPaint.BlendMode.DST_OUT,
+                BrushPaint.BlendMode.SRC_ATOP,
+                BrushPaint.BlendMode.SRC_IN,
+                BrushPaint.BlendMode.SRC_OVER,
+            )
+        assertThat(set).hasSize(6)
+    }
+
+    @Test
+    fun textureBlendModeHashCode_withIdenticalValues_match() {
+        assertThat(BrushPaint.BlendMode.MODULATE.hashCode())
+            .isEqualTo(BrushPaint.BlendMode.MODULATE.hashCode())
+    }
+
+    @Test
+    fun textureBlendModeEquals_checksEqualityOfValues() {
+        assertThat(BrushPaint.BlendMode.MODULATE).isEqualTo(BrushPaint.BlendMode.MODULATE)
+        assertThat(BrushPaint.BlendMode.MODULATE).isNotEqualTo(BrushPaint.BlendMode.SRC_OVER)
+    }
+
+    @Test
+    fun textureBlendModeToString_returnsCorrectString() {
+        assertThat(BrushPaint.BlendMode.MODULATE.toString()).contains("MODULATE")
+        assertThat(BrushPaint.BlendMode.DST_IN.toString()).contains("DST_IN")
+        assertThat(BrushPaint.BlendMode.DST_OUT.toString()).contains("DST_OUT")
+        assertThat(BrushPaint.BlendMode.SRC_ATOP.toString()).contains("SRC_ATOP")
+        assertThat(BrushPaint.BlendMode.SRC_IN.toString()).contains("SRC_IN")
+        assertThat(BrushPaint.BlendMode.SRC_OVER.toString()).contains("SRC_OVER")
+    }
+
+    // endregion
+
+    private external fun matchesNativeCustomPaint(
+        brushPaintNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    private fun makeTestTextureUri(version: Int = 0) =
+        "ink://ink/texture:test-texture" + if (version == 0) "" else ":" + version
+
+    private fun makeTestTextureLayer() =
+        BrushPaint.TextureLayer(
+            colorTextureUri = makeTestTextureUri(),
+            sizeX = 128F,
+            sizeY = 128F,
+            offsetX = 0.1f,
+            offsetY = 0.2f,
+            rotation = Angle.QUARTER_TURN_RADIANS,
+            opacity = 0.3f,
+            BrushPaint.TextureSizeUnit.BRUSH_SIZE,
+            BrushPaint.TextureOrigin.FIRST_STROKE_INPUT,
+            BrushPaint.TextureMapping.WINDING,
+            BrushPaint.BlendMode.SRC_IN,
+        )
+
+    private fun makeTestPaint() = BrushPaint(listOf(makeTestTextureLayer()))
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTest.kt
index 4e1045f..ac8768e 100644
--- a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTest.kt
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -17,20 +17,392 @@
 package androidx.ink.brush
 
 import androidx.ink.brush.color.Color
-import kotlin.test.Test
-import kotlin.test.assertEquals
+import androidx.ink.brush.color.colorspace.ColorSpaces
+import androidx.ink.brush.color.toArgb
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
 
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
 class BrushTest {
+    private val size = 10F
+    private val epsilon = 1F
+    private val color = Color(red = 230, green = 115, blue = 140, alpha = 255)
+    private val family = BrushFamily(uri = "/brush-family:inkpen:1")
+
     @Test
-    fun testSetAndGetColor() {
-        val originalColor = Color.Cyan.value.toLong()
-        val brush = Brush(color = originalColor, size = 2.5f)
-        assertEquals(brush.color, originalColor)
+    fun constructor_withValidArguments_returnsABrush() {
+        val brush = Brush.withColorLong(family, color.value.toLong(), size, epsilon)
+        assertThat(brush).isNotNull()
+        assertThat(brush.family).isEqualTo(family)
+        assertThat(brush.colorLong).isEqualTo(color.value.toLong())
+        assertThat(brush.colorInt).isEqualTo(color.toArgb())
+        assertThat(brush.colorLong).isEqualTo(color.value.toLong())
+        assertThat(brush.size).isEqualTo(size)
+        assertThat(brush.epsilon).isEqualTo(epsilon)
     }
 
     @Test
-    fun testSetAndGetSize() {
-        val brush = Brush(color = Color.DarkGray.value.toLong(), size = 2.5f)
-        assertEquals(brush.size, 2.5f)
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withBadSize_willThrow() {
+        assertFailsWith {
+            Brush(family, color, -2F, epsilon) // non-positive size.
+        }
+
+        assertFailsWith {
+            Brush(family, color, Float.POSITIVE_INFINITY, epsilon) // non-finite size.
+        }
+
+        assertFailsWith {
+            Brush(family, color, Float.NaN, epsilon) // non-finite size.
+        }
     }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withBadEpsilon_willThrow() {
+        assertFailsWith {
+            Brush(family, color, size, -2F) // non-positive epsilon.
+        }
+
+        assertFailsWith {
+            Brush(family, color, size, Float.POSITIVE_INFINITY) // non-finite epsilon.
+        }
+
+        assertFailsWith {
+            Brush(family, color, size, Float.NaN) // non-finite epsilon.
+        }
+    }
+
+    @Test
+    fun colorAccessors_areAllEquivalent() {
+        val color = Color(red = 230, green = 115, blue = 140, alpha = 196)
+        val brush = Brush.withColorLong(family, color.value.toLong(), size, epsilon)
+
+        assertThat(brush.colorInt).isEqualTo(color.toArgb())
+        assertThat(brush.colorLong).isEqualTo(color.value.toLong())
+    }
+
+    @Test
+    fun withColorIntArgb_withLowAlpha_returnsBrushWithCorrectColor() {
+        val brush = Brush.withColorIntArgb(family, 0x12345678, size, epsilon)
+        assertThat(brush.colorInt).isEqualTo(0x12345678)
+    }
+
+    @Test
+    fun withColorIntArgb_withHighAlpha_returnsBrushWithCorrectColor() {
+        val brush = Brush.withColorIntArgb(family, 0xAA123456.toInt(), size, epsilon)
+        assertThat(brush.colorInt).isEqualTo(0xAA123456.toInt())
+    }
+
+    @Test
+    fun withColorLong_returnsBrushWithCorrectColor() {
+        val colorLong = Color(0.9f, 0.45f, 0.55f, 0.15f, ColorSpaces.DisplayP3).value.toLong()
+        val brush = Brush.withColorLong(family, colorLong, size, epsilon)
+        assertThat(brush.colorLong).isEqualTo(colorLong)
+    }
+
+    @Test
+    fun withColorLong_inUnsupportedColorSpace_returnsBrushWithConvertedColor() {
+        val colorLong = Color(0.9f, 0.45f, 0.55f, 0.15f, ColorSpaces.AdobeRgb).value.toLong()
+        val brush = Brush.withColorLong(family, colorLong, size, epsilon)
+
+        val expectedColor = Color(colorLong.toULong()).convert(ColorSpaces.DisplayP3)
+        assertThat(brush.colorLong).isEqualTo(expectedColor.value.toLong())
+        assertThat(brush.colorInt).isEqualTo(expectedColor.toArgb())
+    }
+
+    @Test
+    fun equals_returnsTrueForIdenticalBrushes() {
+        val brush = Brush(family, color, size, epsilon)
+        val otherBrush = Brush(family, color, size, epsilon)
+        assertThat(brush == brush).isTrue()
+        assertThat(brush == otherBrush).isTrue()
+        assertThat(otherBrush == brush).isTrue()
+    }
+
+    @Test
+    fun hashCode_isEqualForIdenticalBrushes() {
+        val brush = Brush(family, color, size, epsilon)
+        val otherBrush = Brush(family, color, size, epsilon)
+        assertThat(brush == brush).isTrue()
+        assertThat(brush == otherBrush).isTrue()
+        assertThat(otherBrush == brush).isTrue()
+    }
+
+    @Test
+    fun equals_returnsFalseIfAnyFieldsDiffer() {
+        val brush = Brush(family, color, size, epsilon)
+
+        val differentFamilyBrush =
+            Brush(BrushFamily(uri = "/brush-family:pencil:1"), color, size, epsilon)
+        assertThat(brush == differentFamilyBrush).isFalse()
+        assertThat(differentFamilyBrush == brush).isFalse()
+        assertThat(brush != differentFamilyBrush).isTrue()
+        assertThat(differentFamilyBrush != brush).isTrue()
+
+        val otherColor =
+            Color(red = 1F, green = 0F, blue = 0F, alpha = 1F, colorSpace = ColorSpaces.DisplayP3)
+                .value
+                .toLong()
+        val differentcolorBrush = Brush.withColorLong(family, otherColor, size, epsilon)
+        assertThat(brush == differentcolorBrush).isFalse()
+        assertThat(differentcolorBrush == brush).isFalse()
+        assertThat(brush != differentcolorBrush).isTrue()
+        assertThat(differentcolorBrush != brush).isTrue()
+
+        val differentSizeBrush = Brush(family, color, 9.0f, epsilon)
+        assertThat(brush == differentSizeBrush).isFalse()
+        assertThat(differentSizeBrush == brush).isFalse()
+        assertThat(brush != differentSizeBrush).isTrue()
+        assertThat(differentSizeBrush != brush).isTrue()
+
+        val differentEpsilonBrush = Brush(family, color, size, 1.1f)
+        assertThat(brush == differentEpsilonBrush).isFalse()
+        assertThat(differentEpsilonBrush == brush).isFalse()
+        assertThat(brush != differentEpsilonBrush).isTrue()
+        assertThat(differentEpsilonBrush != brush).isTrue()
+    }
+
+    @Test
+    fun hashCode_differsIfAnyFieldsDiffer() {
+        val brush = Brush(family, color, size, epsilon)
+
+        val differentFamilyBrush =
+            Brush(BrushFamily(uri = "/brush-family:pencil:1"), color, size, epsilon)
+        assertThat(differentFamilyBrush.hashCode()).isNotEqualTo(brush.hashCode())
+
+        val otherColor =
+            Color(red = 1F, green = 0F, blue = 0F, alpha = 1F, colorSpace = ColorSpaces.DisplayP3)
+                .value
+                .toLong()
+        val differentcolorBrush = Brush.withColorLong(family, otherColor, size, epsilon)
+        assertThat(differentcolorBrush.hashCode()).isNotEqualTo(brush.hashCode())
+
+        val differentSizeBrush = Brush(family, color, 9.0f, epsilon)
+        assertThat(differentSizeBrush.hashCode()).isNotEqualTo(brush.hashCode())
+
+        val differentEpsilonBrush = Brush(family, color, size, 1.1f)
+        assertThat(differentEpsilonBrush.hashCode()).isNotEqualTo(brush.hashCode())
+    }
+
+    @Test
+    fun copy_returnsTheSameBrush() {
+        val originalBrush = buildTestBrush()
+
+        val newBrush = originalBrush.copy()
+
+        // A pure copy returns `this`.
+        assertThat(newBrush).isSameInstanceAs(originalBrush)
+    }
+
+    @Test
+    fun copy_withChangedBrushFamily_returnsCopyWithDifferentBrushFamily() {
+        val originalBrush = buildTestBrush()
+
+        val newBrush = originalBrush.copy(family = BrushFamily())
+
+        assertThat(newBrush).isNotEqualTo(originalBrush)
+        assertThat(newBrush.family).isNotEqualTo(originalBrush.family)
+
+        // The new brush has the original color, size and epsilon.
+        assertThat(newBrush.colorLong).isEqualTo(originalBrush.colorLong)
+        assertThat(newBrush.size).isEqualTo(originalBrush.size)
+        assertThat(newBrush.epsilon).isEqualTo(originalBrush.epsilon)
+    }
+
+    @Test
+    fun copyWithColorIntArgb_withLowAlpha_returnsCopyWithThatColor() {
+        val originalBrush = buildTestBrush()
+
+        val newBrush = originalBrush.copyWithColorIntArgb(colorIntArgb = 0x12345678)
+
+        assertThat(newBrush).isNotEqualTo(originalBrush)
+        assertThat(newBrush.colorLong).isNotEqualTo(originalBrush.colorLong)
+        assertThat(newBrush.colorInt).isEqualTo(0x12345678)
+
+        // The new brush has the original family, size and epsilon.
+        assertThat(newBrush.family).isSameInstanceAs(originalBrush.family)
+        assertThat(newBrush.size).isEqualTo(originalBrush.size)
+        assertThat(newBrush.epsilon).isEqualTo(originalBrush.epsilon)
+    }
+
+    @Test
+    fun copyWithColorIntArgb_withHighAlpha_returnsCopyWithThatColor() {
+        val originalBrush = buildTestBrush()
+
+        val newBrush = originalBrush.copyWithColorIntArgb(colorIntArgb = 0xAA123456.toInt())
+
+        assertThat(newBrush).isNotEqualTo(originalBrush)
+        assertThat(newBrush.colorLong).isNotEqualTo(originalBrush.colorLong)
+        assertThat(newBrush.colorInt).isEqualTo(0xAA123456.toInt())
+
+        // The new brush has the original family, size and epsilon.
+        assertThat(newBrush.family).isSameInstanceAs(originalBrush.family)
+        assertThat(newBrush.size).isEqualTo(originalBrush.size)
+        assertThat(newBrush.epsilon).isEqualTo(originalBrush.epsilon)
+    }
+
+    @Test
+    fun copyWithColorLong_withChangedColor_returnsCopyWithThatColor() {
+        val originalBrush = buildTestBrush()
+
+        val newColor = Color(red = 255, green = 230, blue = 115, alpha = 140).value.toLong()
+        val newBrush = originalBrush.copyWithColorLong(colorLong = newColor)
+
+        assertThat(newBrush).isNotEqualTo(originalBrush)
+        assertThat(newBrush.colorLong).isNotEqualTo(originalBrush.colorLong)
+        assertThat(newBrush.colorLong).isEqualTo(newColor)
+
+        // The new brush has the original family, size and epsilon.
+        assertThat(newBrush.family).isSameInstanceAs(originalBrush.family)
+        assertThat(newBrush.size).isEqualTo(originalBrush.size)
+        assertThat(newBrush.epsilon).isEqualTo(originalBrush.epsilon)
+    }
+
+    @Test
+    fun copyWithColorLong_inUnsupportedColorSpace_returnsCopyWithConvertedColor() {
+        val originalBrush = buildTestBrush()
+
+        val newColor = Color(0.9f, 0.45f, 0.55f, 0.15f, ColorSpaces.AdobeRgb).value.toLong()
+        val newBrush = originalBrush.copyWithColorLong(colorLong = newColor)
+
+        val expectedColor = Color(newColor.toULong()).convert(ColorSpaces.DisplayP3)
+        assertThat(newBrush.colorLong).isEqualTo(expectedColor.value.toLong())
+        assertThat(newBrush.colorInt).isEqualTo(expectedColor.toArgb())
+    }
+
+    @Test
+    fun brushBuilderBuild_withColorIntWithLowAlpha_createsExpectedBrush() {
+        val testBrush = buildTestBrush()
+
+        val builtBrush =
+            Brush.builder()
+                .setFamily(testBrush.family)
+                .setColorIntArgb(0x12345678)
+                .setSize(9f)
+                .setEpsilon(0.9f)
+                .build()
+
+        assertThat(builtBrush.family).isEqualTo(testBrush.family)
+        assertThat(builtBrush.colorInt).isEqualTo(0x12345678)
+        assertThat(builtBrush.size).isEqualTo(9f)
+        assertThat(builtBrush.epsilon).isEqualTo(0.9f)
+    }
+
+    @Test
+    fun brushBuilderBuild_withColorIntWithHighAlpha_createsExpectedBrush() {
+        val testBrush = buildTestBrush()
+
+        val builtBrush =
+            Brush.builder()
+                .setFamily(testBrush.family)
+                .setColorIntArgb(0xAA123456.toInt())
+                .setSize(9f)
+                .setEpsilon(0.9f)
+                .build()
+
+        assertThat(builtBrush.family).isEqualTo(testBrush.family)
+        assertThat(builtBrush.colorInt).isEqualTo(0xAA123456.toInt())
+        assertThat(builtBrush.size).isEqualTo(9f)
+        assertThat(builtBrush.epsilon).isEqualTo(0.9f)
+    }
+
+    @Test
+    fun brushBuilderBuild_withColorLong_createsExpectedBrush() {
+        val testBrush = buildTestBrush()
+        val testColorLong = Color(0.9f, 0.45f, 0.55f, 0.15f, ColorSpaces.DisplayP3).value.toLong()
+
+        val builtBrush =
+            Brush.builder()
+                .setFamily(testBrush.family)
+                .setColorLong(testColorLong)
+                .setSize(9f)
+                .setEpsilon(0.9f)
+                .build()
+
+        assertThat(builtBrush.family).isEqualTo(testBrush.family)
+        assertThat(builtBrush.colorLong).isEqualTo(testColorLong)
+        assertThat(builtBrush.size).isEqualTo(9f)
+        assertThat(builtBrush.epsilon).isEqualTo(0.9f)
+    }
+
+    @Test
+    fun brushBuilderBuild_withUnsupportedColorSpace_createsBrushWithConvertedColor() {
+        val testBrush = buildTestBrush()
+        val testColorLong = Color(0.9f, 0.45f, 0.55f, 0.15f, ColorSpaces.AdobeRgb).value.toLong()
+
+        val builtBrush =
+            Brush.builder()
+                .setFamily(testBrush.family)
+                .setColorLong(testColorLong)
+                .setSize(9f)
+                .setEpsilon(0.9f)
+                .build()
+
+        val expectedColor = Color(testColorLong.toULong()).convert(ColorSpaces.DisplayP3)
+        assertThat(builtBrush.family).isEqualTo(testBrush.family)
+        assertThat(builtBrush.colorLong).isEqualTo(expectedColor.value.toLong())
+        assertThat(builtBrush.size).isEqualTo(9f)
+        assertThat(builtBrush.epsilon).isEqualTo(0.9f)
+    }
+
+    /**
+     * Creates an expected C++ Brush with default brush family/color and returns true if every
+     * property of the Kotlin Brush's JNI-created C++ counterpart is equivalent to the expected C++
+     * Brush.
+     */
+    private external fun matchesDefaultBrush(
+        actualBrushNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /**
+     * Creates an expected C++ Brush with custom values and returns true if every property of the
+     * Kotlin Brush's JNI-created C++ counterpart is equivalent to the expected C++ Brush.
+     */
+    private external fun matchesCustomBrush(
+        actualBrushNativePointer: Long
+    ): Boolean // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+
+    /** Brush with every field different from default values. */
+    private fun buildTestBrush(): Brush =
+        Brush(
+            BrushFamily(
+                tip =
+                    BrushTip(
+                        0.1f,
+                        0.2f,
+                        0.3f,
+                        0.4f,
+                        0.5f,
+                        0.6f,
+                        0.7f,
+                        0.8f,
+                        9L,
+                        listOf(
+                            BrushBehavior(
+                                source = BrushBehavior.Source.TILT_IN_RADIANS,
+                                target = BrushBehavior.Target.HEIGHT_MULTIPLIER,
+                                sourceValueRangeLowerBound = 0.2f,
+                                sourceValueRangeUpperBound = .8f,
+                                targetModifierRangeLowerBound = 1.1f,
+                                targetModifierRangeUpperBound = 1.7f,
+                                sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.MIRROR,
+                                responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+                                responseTimeMillis = 1L,
+                                enabledToolTypes = setOf(InputToolType.STYLUS),
+                                isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+                            )
+                        ),
+                    ),
+                paint = BrushPaint(),
+                uri = "/brush-family:marker:1",
+            ),
+            color,
+            13F,
+            0.1234F,
+        )
 }
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTipTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTipTest.kt
new file mode 100644
index 0000000..2e54338
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/BrushTipTest.kt
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.ink.geometry.Angle
+import com.google.common.truth.Truth.assertThat
+import kotlin.IllegalArgumentException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class BrushTipTest {
+    /** Brush behavior with every field different from default values. */
+    private val customBehavior =
+        BrushBehavior(
+            source = BrushBehavior.Source.TILT_IN_RADIANS,
+            target = BrushBehavior.Target.HEIGHT_MULTIPLIER,
+            sourceValueRangeLowerBound = 0.2f,
+            sourceValueRangeUpperBound = .8f,
+            targetModifierRangeLowerBound = 1.1f,
+            targetModifierRangeUpperBound = 1.7f,
+            sourceOutOfRangeBehavior = BrushBehavior.OutOfRange.MIRROR,
+            responseCurve = EasingFunction.Predefined.EASE_IN_OUT,
+            responseTimeMillis = 1L,
+            enabledToolTypes = setOf(InputToolType.STYLUS),
+            isFallbackFor = BrushBehavior.OptionalInputProperty.TILT_X_AND_Y,
+        )
+
+    @Test
+    fun constructor_returnsExpectedValues() {
+        val brushTip = BrushTip()
+        assertThat(brushTip.scaleX).isEqualTo(1f)
+        assertThat(brushTip.scaleY).isEqualTo(1f)
+        assertThat(brushTip.cornerRounding).isEqualTo(1f)
+        assertThat(brushTip.slant).isEqualTo(Angle.ZERO)
+        assertThat(brushTip.pinch).isEqualTo(0.0f)
+        assertThat(brushTip.rotation).isEqualTo(Angle.ZERO)
+        assertThat(brushTip.opacityMultiplier).isEqualTo(1.0f)
+        assertThat(brushTip.particleGapDistanceScale).isEqualTo(0.0f)
+        assertThat(brushTip.particleGapDurationMillis).isEqualTo(0L)
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidScaleX_throws() {
+        val infinityError =
+            assertFailsWith { BrushTip(scaleX = Float.POSITIVE_INFINITY) }
+        assertThat(infinityError).hasMessageThat().contains("scale")
+        assertThat(infinityError).hasMessageThat().contains("finite")
+
+        val nanError = assertFailsWith { BrushTip(scaleX = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("scale")
+        assertThat(nanError).hasMessageThat().contains("finite")
+
+        val negativeError = assertFailsWith { BrushTip(scaleX = -1.0f) }
+        assertThat(negativeError).hasMessageThat().contains("scale")
+        assertThat(negativeError).hasMessageThat().contains("non-negative")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidScaleY_throws() {
+        val infinityError =
+            assertFailsWith { BrushTip(scaleY = Float.POSITIVE_INFINITY) }
+        assertThat(infinityError).hasMessageThat().contains("scale")
+        assertThat(infinityError).hasMessageThat().contains("finite")
+
+        val nanError = assertFailsWith { BrushTip(scaleY = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("scale")
+        assertThat(nanError).hasMessageThat().contains("finite")
+
+        val negativeError = assertFailsWith { BrushTip(scaleY = -1.0f) }
+        assertThat(negativeError).hasMessageThat().contains("scale")
+        assertThat(negativeError).hasMessageThat().contains("non-negative")
+    }
+
+    @Test
+    fun constructor_withZeroScale_throws() {
+        val zeroError =
+            assertFailsWith { BrushTip(scaleX = 0f, scaleY = 0f) }
+        assertThat(zeroError).hasMessageThat().contains("at least one value must be positive.")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidCornerRounding_throws() {
+        val nanError =
+            assertFailsWith { BrushTip(cornerRounding = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("corner_rounding")
+        assertThat(nanError).hasMessageThat().contains("in the interval [0, 1]")
+
+        val lowError =
+            assertFailsWith { BrushTip(cornerRounding = -0.5f) }
+        assertThat(lowError).hasMessageThat().contains("corner_rounding")
+        assertThat(lowError).hasMessageThat().contains("in the interval [0, 1]")
+
+        val highError =
+            assertFailsWith { BrushTip(cornerRounding = 1.1f) }
+        assertThat(highError).hasMessageThat().contains("corner_rounding")
+        assertThat(highError).hasMessageThat().contains("in the interval [0, 1]")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidSlant_throws() {
+        val nanError = assertFailsWith { BrushTip(slant = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("slant")
+        assertThat(nanError).hasMessageThat().contains("finite")
+
+        val lowError =
+            assertFailsWith { BrushTip(slant = -Angle.HALF_TURN_RADIANS) }
+        assertThat(lowError).hasMessageThat().contains("slant")
+        assertThat(lowError).hasMessageThat().contains("interval [-pi/2, pi/2]")
+
+        val highError =
+            assertFailsWith { BrushTip(slant = Angle.HALF_TURN_RADIANS) }
+        assertThat(highError).hasMessageThat().contains("slant")
+        assertThat(highError).hasMessageThat().contains("interval [-pi/2, pi/2]")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidPinch_throws() {
+        val nanError = assertFailsWith { BrushTip(pinch = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("pinch")
+        assertThat(nanError).hasMessageThat().contains("interval [0, 1]")
+
+        val lowError = assertFailsWith { BrushTip(pinch = -0.1f) }
+        assertThat(lowError).hasMessageThat().contains("pinch")
+        assertThat(lowError).hasMessageThat().contains("interval [0, 1]")
+
+        val highError = assertFailsWith { BrushTip(pinch = 1.1f) }
+        assertThat(highError).hasMessageThat().contains("pinch")
+        assertThat(highError).hasMessageThat().contains("interval [0, 1]")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidOpacitiyMultiplier_throws() {
+        val nanError =
+            assertFailsWith { BrushTip(opacityMultiplier = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("opacity_multiplier")
+        assertThat(nanError).hasMessageThat().contains("interval [0, 2]")
+
+        val lowError =
+            assertFailsWith { BrushTip(opacityMultiplier = -0.1f) }
+        assertThat(lowError).hasMessageThat().contains("opacity_multiplier")
+        assertThat(lowError).hasMessageThat().contains("interval [0, 2]")
+
+        val highError =
+            assertFailsWith { BrushTip(opacityMultiplier = 2.1f) }
+        assertThat(highError).hasMessageThat().contains("opacity_multiplier")
+        assertThat(highError).hasMessageThat().contains("interval [0, 2]")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidParticleGapDistanceScale_throws() {
+        val infinityError =
+            assertFailsWith {
+                BrushTip(particleGapDistanceScale = Float.POSITIVE_INFINITY)
+            }
+        assertThat(infinityError).hasMessageThat().contains("particle_gap_distance_scale")
+        assertThat(infinityError).hasMessageThat().contains("finite")
+
+        val nanError =
+            assertFailsWith {
+                BrushTip(particleGapDistanceScale = Float.NaN)
+            }
+        assertThat(nanError).hasMessageThat().contains("particle_gap_distance_scale")
+        assertThat(nanError).hasMessageThat().contains("finite")
+
+        val negativeError =
+            assertFailsWith { BrushTip(particleGapDistanceScale = -1.0f) }
+        assertThat(negativeError).hasMessageThat().contains("particle_gap_distance_scale")
+        assertThat(negativeError).hasMessageThat().contains("non-negative")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidParticleGapDurationMillis_throws() {
+        val negativeError =
+            assertFailsWith { BrushTip(particleGapDurationMillis = -1L) }
+        assertThat(negativeError).hasMessageThat().contains("particle_gap_duration")
+        assertThat(negativeError).hasMessageThat().contains("non-negative")
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun constructor_withInvalidRotation_throws() {
+        val nanError = assertFailsWith { BrushTip(rotation = Float.NaN) }
+        assertThat(nanError).hasMessageThat().contains("rotation")
+        assertThat(nanError).hasMessageThat().contains("finite")
+
+        val infinityError =
+            assertFailsWith {
+                BrushTip(rotation = Float.POSITIVE_INFINITY)
+            }
+        assertThat(infinityError).hasMessageThat().contains("rotation")
+        assertThat(infinityError).hasMessageThat().contains("finite")
+    }
+
+    @Test
+    fun hashCode_withIdenticalValues_matches() {
+        // same values.
+        assertThat(
+                BrushTip(
+                        1f,
+                        2f,
+                        0.3f,
+                        Angle.QUARTER_TURN_RADIANS,
+                        0.4f,
+                        Angle.ZERO,
+                        0.7f,
+                        0.5f,
+                        100L,
+                        emptyList(),
+                    )
+                    .hashCode()
+            )
+            .isEqualTo(
+                BrushTip(
+                        1f,
+                        2f,
+                        0.3f,
+                        Angle.QUARTER_TURN_RADIANS,
+                        0.4f,
+                        Angle.ZERO,
+                        0.7f,
+                        0.5f,
+                        100L,
+                        emptyList(),
+                    )
+                    .hashCode()
+            )
+    }
+
+    @Test
+    fun equals_comparesValues() {
+        val brushTip = BrushTip()
+        // same values.
+        assertThat(brushTip).isEqualTo(BrushTip())
+
+        // different values.
+        assertThat(brushTip).isNotEqualTo(null)
+        assertThat(brushTip).isNotEqualTo(Any())
+        assertThat(brushTip).isNotEqualTo(BrushTip(scaleX = 2f))
+        assertThat(brushTip).isNotEqualTo(BrushTip(scaleY = 2f))
+        assertThat(brushTip).isNotEqualTo(BrushTip(cornerRounding = 0.2f))
+        assertThat(brushTip).isNotEqualTo(BrushTip(slant = Angle.QUARTER_TURN_RADIANS))
+        assertThat(brushTip).isNotEqualTo(BrushTip(pinch = 0.2f))
+        assertThat(brushTip).isNotEqualTo(BrushTip(rotation = Angle.HALF_TURN_RADIANS))
+        assertThat(brushTip).isNotEqualTo(BrushTip(opacityMultiplier = 0.7f))
+        assertThat(brushTip).isNotEqualTo(BrushTip(behaviors = listOf(customBehavior)))
+    }
+
+    @Test
+    fun toString_returnsExpectedValues() {
+        assertThat(BrushTip().toString())
+            .isEqualTo(
+                "BrushTip(scale=(1.0, 1.0), cornerRounding=1.0, slant=0.0, " +
+                    "pinch=0.0, rotation=0.0, opacityMultiplier=1.0, " +
+                    "particleGapDistanceScale=0.0, particleGapDurationMillis=0, " +
+                    "behaviors=[])"
+            )
+    }
+
+    @Test
+    fun copy_withArguments_createsCopyWithChanges() {
+        val tip1 =
+            BrushTip(
+                scaleX = 2f,
+                scaleY = 3f,
+                cornerRounding = 0.5f,
+                slant = Angle.ZERO,
+                pinch = 0.5f,
+                rotation = Angle.ZERO,
+                opacityMultiplier = 0.7f,
+                particleGapDistanceScale = 0.8f,
+                particleGapDurationMillis = 9L,
+                behaviors = listOf(customBehavior),
+            )
+
+        assertThat(tip1.copy(scaleX = 3f))
+            .isEqualTo(
+                BrushTip(
+                    scaleX = 3f,
+                    scaleY = 3f,
+                    cornerRounding = 0.5f,
+                    slant = Angle.ZERO,
+                    pinch = 0.5f,
+                    rotation = Angle.ZERO,
+                    opacityMultiplier = 0.7f,
+                    particleGapDistanceScale = 0.8f,
+                    particleGapDurationMillis = 9L,
+                    behaviors = listOf(customBehavior),
+                )
+            )
+    }
+
+    @Test
+    fun copy_createsCopy() {
+        val tip1 =
+            BrushTip(
+                scaleX = 3f,
+                scaleY = 3f,
+                cornerRounding = 0.5f,
+                slant = Angle.ZERO,
+                pinch = 0.5f,
+                rotation = Angle.ZERO,
+                opacityMultiplier = 0.7f,
+                particleGapDistanceScale = 0.8f,
+                particleGapDurationMillis = 9L,
+                behaviors = listOf(customBehavior),
+            )
+
+        val tip2 = tip1.copy()
+
+        assertThat(tip2).isEqualTo(tip1)
+        assertThat(tip2.nativePointer).isNotEqualTo(tip1.nativePointer)
+        assertThat(tip2).isNotSameInstanceAs(tip1)
+    }
+
+    @Test
+    fun builder_createsExpectedBrushTip() {
+        val tip =
+            BrushTip.Builder()
+                .setScaleX(0.1f)
+                .setScaleY(0.2f)
+                .setCornerRounding(0.3f)
+                .setSlant(0.4f)
+                .setPinch(0.5f)
+                .setRotation(0.6f)
+                .setOpacityMultiplier(0.7f)
+                .setParticleGapDistanceScale(0.8f)
+                .setParticleGapDurationMillis(9L)
+                .setBehaviors(listOf(customBehavior))
+                .build()
+
+        assertThat(tip)
+            .isEqualTo(
+                BrushTip(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 9L, listOf(customBehavior))
+            )
+    }
+
+    /**
+     * Creates an expected C++ BrushTip with no behaviors and returns true if every property of the
+     * Kotlin BrushTip's JNI-created C++ counterpart is equivalent to the expected C++ BrushTip.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeNoBehaviorTip(nativePointerToActualBrushTip: Long): Boolean
+
+    /**
+     * Creates an expected C++ BrushTip with a single behavior and returns true if every property of
+     * the Kotlin BrushTip's JNI-created C++ counterpart is equivalent to the expected C++ BrushTip.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeSingleBehaviorTip(
+        nativePointerToActualBrushTip: Long
+    ): Boolean
+
+    /**
+     * Creates an expected C++ BrushTip with multiple behaviors and returns true if every property
+     * of the Kotlin BrushTip's JNI-created C++ counterpart is equivalent to the expected C++
+     * BrushTip.
+     */
+    // TODO: b/355248266 - @Keep must go in Proguard config file instead.
+    private external fun matchesNativeMultiBehaviorTip(nativePointerToActualBrushTip: Long): Boolean
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/ColorExtensionsTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/ColorExtensionsTest.kt
new file mode 100644
index 0000000..e85b662
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/ColorExtensionsTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.ink.brush.color.Color as ComposeColor
+import androidx.ink.brush.color.colorspace.ColorSpaces as ComposeColorSpaces
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ColorExtensionsTest {
+    @Test
+    fun composeColorToColorInInkSupportedColorSpace_withSupportedColorSpace_returnsSameColor() {
+        val composeColor =
+            ComposeColor(
+                red = 0f,
+                green = 1f,
+                blue = 100f / 255f,
+                alpha = 155f / 255f,
+                colorSpace = ComposeColorSpaces.DisplayP3,
+            )
+
+        val convertedColor = composeColor.toColorInInkSupportedColorSpace()
+
+        // The color space is supported, so the color is the same. It's not the same instance,
+        // though,
+        // since ComposeColor is a value class.
+        assertThat(convertedColor).isEqualTo(composeColor)
+    }
+
+    @Test
+    fun composeColorToColorInInkSupportedColorSpace_withUnsupportedColorSpace_convertsToDisplayP3() {
+        val composeColor =
+            ComposeColor(
+                red = 0f,
+                green = 1f,
+                blue = 100f / 255f,
+                alpha = 155f / 255f,
+                colorSpace = ComposeColorSpaces.AdobeRgb,
+            )
+
+        val convertedColor = composeColor.toColorInInkSupportedColorSpace()
+
+        // The color space got converted to DISPLAY_P3. The color is out of gamut, so it got scaled
+        // into
+        // the Display P3 gamut.
+        assertThat(convertedColor.colorSpace).isEqualTo(ComposeColorSpaces.DisplayP3)
+        assertThat(convertedColor.red).isWithin(0.001f).of(0f)
+        assertThat(convertedColor.green).isWithin(0.001f).of(0.9795f)
+        assertThat(convertedColor.blue).isWithin(0.001f).of(0.4204f)
+        assertThat(convertedColor.alpha).isWithin(0.001f).of(155f / 255f)
+    }
+
+    @Test
+    fun composeColorSpaceToInkColorSpaceId_converts() {
+        assertThat(ComposeColorSpaces.Srgb.toInkColorSpaceId()).isEqualTo(0)
+        assertThat(ComposeColorSpaces.DisplayP3.toInkColorSpaceId()).isEqualTo(1)
+    }
+
+    @Test
+    fun composeColorSpaceToInkColorSpaceId_withUnsupportedColorSpace_throws() {
+        assertFailsWith {
+            ComposeColorSpaces.AdobeRgb.toInkColorSpaceId()
+        }
+    }
+}
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/EasingFunctionTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/EasingFunctionTest.kt
new file mode 100644
index 0000000..8bf0023
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/EasingFunctionTest.kt
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import androidx.ink.brush.EasingFunction.Predefined
+import androidx.ink.geometry.ImmutableVec
+import com.google.common.truth.Truth.assertThat
+import kotlin.IllegalArgumentException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalInkCustomBrushApi::class)
+@RunWith(JUnit4::class)
+class EasingFunctionTest {
+
+    @Test
+    fun predefinedConstants_areDistinct() {
+        val set =
+            setOf(
+                EasingFunction.Predefined.LINEAR,
+                EasingFunction.Predefined.EASE,
+                EasingFunction.Predefined.EASE_IN,
+                EasingFunction.Predefined.EASE_OUT,
+                EasingFunction.Predefined.EASE_IN_OUT,
+                EasingFunction.Predefined.STEP_START,
+                EasingFunction.Predefined.STEP_END,
+            )
+        assertThat(set.size).isEqualTo(7)
+    }
+
+    @Test
+    fun predefinedToString_returnsCorrectString() {
+        assertThat(Predefined.LINEAR.toString()).isEqualTo("EasingFunction.Predefined.LINEAR")
+        assertThat(Predefined.EASE.toString()).isEqualTo("EasingFunction.Predefined.EASE")
+        assertThat(EasingFunction.Predefined.EASE_IN.toString())
+            .isEqualTo("EasingFunction.Predefined.EASE_IN")
+        assertThat(EasingFunction.Predefined.EASE_OUT.toString())
+            .isEqualTo("EasingFunction.Predefined.EASE_OUT")
+        assertThat(EasingFunction.Predefined.EASE_IN_OUT.toString())
+            .isEqualTo("EasingFunction.Predefined.EASE_IN_OUT")
+        assertThat(EasingFunction.Predefined.STEP_START.toString())
+            .isEqualTo("EasingFunction.Predefined.STEP_START")
+        assertThat(EasingFunction.Predefined.STEP_END.toString())
+            .isEqualTo("EasingFunction.Predefined.STEP_END")
+    }
+
+    @Test
+    fun predefinedHashCode_withIdenticalValues_matches() {
+        assertThat(EasingFunction.Predefined.LINEAR.hashCode())
+            .isEqualTo(EasingFunction.Predefined.LINEAR.hashCode())
+
+        assertThat(EasingFunction.Predefined.LINEAR.hashCode())
+            .isNotEqualTo(EasingFunction.Predefined.STEP_END.hashCode())
+    }
+
+    @Test
+    fun predefinedEquals_checksEqualityOfValues() {
+        assertThat(EasingFunction.Predefined.LINEAR).isEqualTo(EasingFunction.Predefined.LINEAR)
+        assertThat(EasingFunction.Predefined.LINEAR).isNotEqualTo(EasingFunction.Predefined.EASE)
+        assertThat(EasingFunction.Predefined.LINEAR).isNotEqualTo(null)
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun cubicBezierConstructor_requiresValuesInRange() {
+        // arg x1 outside range [0,1]
+        assertFailsWith {
+            EasingFunction.CubicBezier(x1 = 1.1F, 1F, 3F, 4F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(x1 = -0.2F, 3F, 1F, 4F)
+        }
+        // arg x2 outside range [0,1]
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 3F, x2 = 2F, 4F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 3F, x2 = -0.5F, 4F)
+        }
+    }
+
+    @Test
+    @Suppress("Range") // Testing error cases.
+    fun cubicBezierConstructor_requiresFiniteValues() {
+        assertFailsWith {
+            EasingFunction.CubicBezier(x1 = Float.POSITIVE_INFINITY, 1F, 1F, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(x1 = Float.NaN, 1F, 1F, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 1F, x2 = Float.POSITIVE_INFINITY, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 1F, x2 = Float.NaN, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, y1 = Float.POSITIVE_INFINITY, 1F, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, y1 = Float.NaN, 1F, 1F)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 1F, 1F, y2 = Float.POSITIVE_INFINITY)
+        }
+        assertFailsWith {
+            EasingFunction.CubicBezier(1F, 1F, 1F, y2 = Float.NaN)
+        }
+    }
+
+    @Test
+    fun cubicBezierHashCode_withIdenticalValues_matches() {
+        assertThat(EasingFunction.CubicBezier(1f, 2f, 0.3f, 4f).hashCode())
+            .isEqualTo(EasingFunction.CubicBezier(1f, 2f, 0.3f, 4f).hashCode())
+    }
+
+    @Test
+    fun cubicBezierEquals_checksEqualityOfValues() {
+        val original = EasingFunction.CubicBezier(1f, 2f, 0.3f, 4f)
+
+        // Equal
+        assertThat(original).isEqualTo(original) // Same instance.
+        assertThat(original).isEqualTo(EasingFunction.CubicBezier(1f, 2f, 0.3f, 4f)) // Same values.
+
+        // Not equal
+        assertThat(original).isNotEqualTo(null)
+        assertThat(original).isNotEqualTo(EasingFunction.Predefined.LINEAR) // Different type.
+        assertThat(original)
+            .isNotEqualTo(EasingFunction.CubicBezier(0.9f, 0.8f, 0.7f, 0.6f)) // Values.
+    }
+
+    @Test
+    fun cubicBezierToString_returnsReasonableString() {
+        assertThat(EasingFunction.CubicBezier(1f, 2f, 0.3f, 4f).toString())
+            .isEqualTo("EasingFunction.CubicBezier(x1=1.0, y1=2.0, x2=0.3, y2=4.0)")
+    }
+
+    @Test
+    fun linearConstructor_requiresXValuesInRange() {
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(-0.1F, 0.5F)))
+        }
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(1.1F, 0.5F)))
+        }
+    }
+
+    @Test
+    fun linearConstructor_requiresFiniteValues() {
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(Float.POSITIVE_INFINITY, 0.5F)))
+        }
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(Float.NaN, 0.5F)))
+        }
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(0.5F, Float.POSITIVE_INFINITY)))
+        }
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(0.5F, Float.NaN)))
+        }
+    }
+
+    @Test
+    fun linearConstructor_requiresSortedXValues() {
+        assertFailsWith {
+            EasingFunction.Linear(listOf(ImmutableVec(0.75F, 0.5F), ImmutableVec(0.25F, 0.5F)))
+        }
+    }
+
+    @Test
+    fun linearHashCode_withIdenticalValues_matches() {
+        assertThat(EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f))).hashCode())
+            .isEqualTo(EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f))).hashCode())
+    }
+
+    @Test
+    fun linearEquals_checksEqualityOfValues() {
+        val original =
+            EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f), ImmutableVec(0.75f, 0.9f)))
+
+        // Equal
+        assertThat(original).isEqualTo(original) // Same instance.
+        assertThat(original)
+            .isEqualTo(
+                EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f), ImmutableVec(0.75f, 0.9f)))
+            ) // Same values.
+
+        // Not equal
+        assertThat(original).isNotEqualTo(null)
+        assertThat(original).isNotEqualTo(EasingFunction.Predefined.LINEAR) // Different type.
+        assertThat(original)
+            .isNotEqualTo(
+                EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f)))
+            ) // Shorter list of points.
+        assertThat(original)
+            .isNotEqualTo(
+                EasingFunction.Linear(listOf(ImmutableVec(0.15f, 0.1f), ImmutableVec(0.75f, 0.9f)))
+            ) // Different point values.
+        assertThat(original)
+            .isNotEqualTo(
+                EasingFunction.Linear(
+                    listOf(
+                        ImmutableVec(0.25f, 0.1f),
+                        ImmutableVec(0.75f, 0.9f),
+                        ImmutableVec(0.9f, 0.5f)
+                    )
+                )
+            ) // Longer list of points.
+    }
+
+    @Test
+    fun linearToString_returnsReasonableString() {
+        val string =
+            EasingFunction.Linear(listOf(ImmutableVec(0.25f, 0.1f), ImmutableVec(0.75f, 0.9f)))
+                .toString()
+        assertThat(string).contains("EasingFunction.Linear")
+        assertThat(string).contains("Vec")
+        assertThat(string).contains("0.25")
+        assertThat(string).contains("0.1")
+        assertThat(string).contains("0.75")
+        assertThat(string).contains("0.9")
+    }
+
+    @Test
+    fun stepPositionConstants_areDistinct() {
+        val set =
+            setOf(
+                EasingFunction.StepPosition.JUMP_START,
+                EasingFunction.StepPosition.JUMP_END,
+                EasingFunction.StepPosition.JUMP_NONE,
+                EasingFunction.StepPosition.JUMP_BOTH,
+            )
+        assertThat(set.size).isEqualTo(4)
+    }
+
+    @Test
+    fun stepPositionToString_returnsReasonableString() {
+        assertThat(EasingFunction.StepPosition.JUMP_START.toString())
+            .isEqualTo("EasingFunction.StepPosition.JUMP_START")
+        assertThat(EasingFunction.StepPosition.JUMP_END.toString())
+            .isEqualTo("EasingFunction.StepPosition.JUMP_END")
+        assertThat(EasingFunction.StepPosition.JUMP_BOTH.toString())
+            .isEqualTo("EasingFunction.StepPosition.JUMP_BOTH")
+        assertThat(EasingFunction.StepPosition.JUMP_NONE.toString())
+            .isEqualTo("EasingFunction.StepPosition.JUMP_NONE")
+    }
+
+    @Test
+    fun stepPositionHashCode_withIdenticalValues_matches() {
+        assertThat(EasingFunction.StepPosition.JUMP_START.hashCode())
+            .isEqualTo(EasingFunction.StepPosition.JUMP_START.hashCode())
+
+        assertThat(EasingFunction.StepPosition.JUMP_START.hashCode())
+            .isNotEqualTo(EasingFunction.StepPosition.JUMP_END.hashCode())
+    }
+
+    @Test
+    fun steps_withInvalidStepCount_throws() {
+        // Step count less than zero throws.
+        assertFailsWith {
+            EasingFunction.Steps(0, EasingFunction.StepPosition.JUMP_START)
+        }
+        assertFailsWith {
+            EasingFunction.Steps(-1, EasingFunction.StepPosition.JUMP_START)
+        }
+
+        // Step count not greater than 1 for JUMP_NONE throws.
+        assertFailsWith {
+            EasingFunction.Steps(0, EasingFunction.StepPosition.JUMP_NONE)
+        }
+        assertFailsWith {
+            EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_NONE)
+        }
+
+        assertThat(EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_NONE)).isNotNull()
+        assertThat(EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_START)).isNotNull()
+    }
+
+    @Test
+    fun stepsHashCode_withSameValues_match() {
+        assertThat(EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_START).hashCode())
+            .isEqualTo(EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_START).hashCode())
+
+        // Different step count.
+        assertThat(EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_START).hashCode())
+            .isNotEqualTo(
+                EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_START).hashCode()
+            )
+
+        // Different stepPosition.
+        assertThat(EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_START).hashCode())
+            .isNotEqualTo(EasingFunction.Steps(1, EasingFunction.StepPosition.JUMP_END).hashCode())
+    }
+
+    @Test
+    fun stepsEquals_checksEqualityOfValues() {
+        val original = EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_START)
+
+        // Equal
+        assertThat(original).isEqualTo(original) // Same instance.
+        assertThat(original)
+            .isEqualTo(
+                EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_START)
+            ) // Same values.
+
+        // Not equal
+        assertThat(original).isNotEqualTo(null)
+        // Different type.
+        assertThat(original).isNotEqualTo(EasingFunction.Predefined.LINEAR)
+        // Different count.
+        assertThat(original)
+            .isNotEqualTo(EasingFunction.Steps(3, EasingFunction.StepPosition.JUMP_START))
+        // Different position.
+        assertThat(original)
+            .isNotEqualTo(EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_END))
+    }
+
+    @Test
+    fun stepsToString_returnsReasonableString() {
+        assertThat(EasingFunction.Steps(2, EasingFunction.StepPosition.JUMP_START).toString())
+            .isEqualTo(
+                "EasingFunction.Steps(stepCount=2, stepPosition=EasingFunction.StepPosition.JUMP_START)"
+            )
+    }
+}
diff --git a/tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/Empty.kt
similarity index 68%
rename from tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt
rename to ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/Empty.kt
index 3fa6028..0c09d26 100644
--- a/tv/integration-tests/presentation/src/main/java/androidx/tv/integration/presentation/readAssetsFile.kt
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/Empty.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package androidx.tv.integration.presentation
+package androidx.ink.brush
 
-import android.content.res.AssetManager
-
-fun AssetManager.readAssetsFile(fileName: String): String =
-    open(fileName).bufferedReader().use { it.readText() }
+/**
+ * Exists solely so that brush_test_jni_lib can have non-empty srcs, in order to aggregate its
+ * runtime_deps for convenience to the test targets.
+ */
+private class Empty
diff --git a/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/InputToolTypeTest.kt b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/InputToolTypeTest.kt
new file mode 100644
index 0000000..209fa49
--- /dev/null
+++ b/ink/ink-brush/src/jvmAndroidTest/kotlin/androidx/ink/brush/InputToolTypeTest.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 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.ink.brush
+
+import com.google.common.truth.Truth.assertThat
+import kotlin.IllegalArgumentException
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class InputToolTypeTest {
+
+    @Test
+    fun constants_areDistinct() {
+        val set =
+            setOf(
+                InputToolType.UNKNOWN,
+                InputToolType.MOUSE,
+                InputToolType.STYLUS,
+                InputToolType.TOUCH
+            )
+        assertThat(set).hasSize(4)
+    }
+
+    @Test
+    fun toString_returnsCorrectString() {
+        assertThat(InputToolType.UNKNOWN.toString()).isEqualTo("InputToolType.UNKNOWN")
+        assertThat(InputToolType.MOUSE.toString()).isEqualTo("InputToolType.MOUSE")
+        assertThat(InputToolType.TOUCH.toString()).isEqualTo("InputToolType.TOUCH")
+        assertThat(InputToolType.STYLUS.toString()).isEqualTo("InputToolType.STYLUS")
+    }
+
+    @Test
+    fun hashCode_withIdenticalValues_matches() {
+        assertThat(InputToolType.MOUSE.hashCode()).isEqualTo(InputToolType.MOUSE.hashCode())
+
+        assertThat(InputToolType.MOUSE.hashCode()).isNotEqualTo(InputToolType.TOUCH.hashCode())
+    }
+
+    @Test
+    fun equals_checksEqualityOfValues() {
+        assertThat(InputToolType.MOUSE).isEqualTo(InputToolType.MOUSE)
+        assertThat(InputToolType.MOUSE).isNotEqualTo(InputToolType.TOUCH)
+        assertThat(InputToolType.MOUSE).isNotEqualTo(null)
+    }
+
+    @Test
+    fun from_createsCorrectInputToolType() {
+        assertThat(InputToolType.from(0)).isEqualTo(InputToolType.UNKNOWN)
+        assertThat(InputToolType.from(1)).isEqualTo(InputToolType.MOUSE)
+        assertThat(InputToolType.from(2)).isEqualTo(InputToolType.TOUCH)
+        assertThat(InputToolType.from(3)).isEqualTo(InputToolType.STYLUS)
+        assertFailsWith { InputToolType.from(4) }
+    }
+}
diff --git a/ink/ink-geometry/src/androidInstrumentedTest/kotlin/androidx/ink/geometry/EnvelopeExtensionsTest.kt b/ink/ink-geometry/src/androidInstrumentedTest/kotlin/androidx/ink/geometry/EnvelopeExtensionsTest.kt
index 44862ce..f98e981 100644
--- a/ink/ink-geometry/src/androidInstrumentedTest/kotlin/androidx/ink/geometry/EnvelopeExtensionsTest.kt
+++ b/ink/ink-geometry/src/androidInstrumentedTest/kotlin/androidx/ink/geometry/EnvelopeExtensionsTest.kt
@@ -40,7 +40,7 @@
     fun getBoundsRectF_whenHasBounds_returnsTrueAndOverwritesOutParameter() {
         val envelope =
             BoxAccumulator()
-                .add(MutableBox().fillFromTwoPoints(ImmutablePoint(1f, 2f), ImmutablePoint(3f, 4f)))
+                .add(MutableBox().populateFromTwoPoints(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f)))
 
         val outRect = RectF(5F, 6F, 7F, 8F)
         assertThat(envelope.getBounds(outRect)).isTrue()
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Box.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Box.kt
index 314a735..2062961 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Box.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Box.kt
@@ -49,17 +49,18 @@
         @FloatRange(from = 0.0) get() = yMax - yMin
 
     /** Populates [out] with the center of the [Box]. */
-    public fun center(out: MutablePoint)
+    public fun populateCenter(out: MutableVec): Unit =
+        BoxHelper.nativeCenter(xMin, yMin, xMax, yMax, out)
 
     /**
      * Populates the 4 [output] points with the corners of the [Box]. The order of the corners is:
      * (x_min, y_min), (x_max, y_min), (x_max, y_max), (x_min, y_max)
      */
     public fun corners(
-        outputXMinYMin: MutablePoint,
-        outputXMaxYMin: MutablePoint,
-        outputXMaxYMax: MutablePoint,
-        outputXMinYMax: MutablePoint,
+        outputXMinYMin: MutableVec,
+        outputXMaxYMin: MutableVec,
+        outputXMaxYMax: MutableVec,
+        outputXMinYMax: MutableVec,
     ) {
         outputXMinYMin.x = xMin
         outputXMinYMin.y = yMin
@@ -75,7 +76,7 @@
      * Returns whether the given point is contained within the Box. Points that lie exactly on the
      * Box's boundary are considered to be contained.
      */
-    public operator fun contains(point: Point): Boolean =
+    public operator fun contains(point: Vec): Boolean =
         BoxHelper.nativeContainsPoint(xMin, yMin, xMax, yMax, point.x, point.y)
 
     /**
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxAccumulator.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxAccumulator.kt
index acf7fb6..f234c66 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxAccumulator.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxAccumulator.kt
@@ -59,9 +59,9 @@
     ) : this(
         true,
         MutableBox()
-            .fillFromTwoPoints(
-                ImmutablePoint(box.xMin, box.yMin),
-                ImmutablePoint(box.xMax, box.yMax)
+            .populateFromTwoPoints(
+                ImmutableVec(box.xMin, box.yMin),
+                ImmutableVec(box.xMax, box.yMax)
             ),
     )
 
@@ -219,7 +219,7 @@
      * Expands the accumulated bounding box (if necessary) such that it also contains [mesh]. If
      * [mesh] is null or empty, this is a no-op.
      */
-    public fun add(mesh: ModeledShape): BoxAccumulator = this.add(mesh.bounds)
+    public fun add(mesh: PartitionedMesh): BoxAccumulator = this.add(mesh.bounds)
 
     /**
      * Compares this [BoxAccumulator] with [other], and returns true if either: Both this and
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxHelper.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxHelper.kt
index 087e544..68f902b 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxHelper.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/BoxHelper.kt
@@ -31,7 +31,7 @@
         rectYMin: Float,
         rectXMax: Float,
         rectYMax: Float,
-        out: MutablePoint,
+        out: MutableVec,
     )
 
     // TODO: b/355248266 - @Keep must go in Proguard config file instead.
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableBox.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableBox.kt
index 163c613..a654ad8 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableBox.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableBox.kt
@@ -43,35 +43,6 @@
     /** The upper bound in the `Y` direction. */
     override val yMax: Float = max(y1, y2)
 
-    public fun fillMutable(output: MutableBox) {
-        output.setXBounds(xMin, xMax).setYBounds(yMin, yMax)
-    }
-
-    public fun newMutable(): MutableBox {
-        return MutableBox().setXBounds(xMin, xMax).setYBounds(yMin, yMax)
-    }
-
-    /** Populates [out] with the center of the [ImmutableBox]. */
-    override fun center(out: MutablePoint): Unit =
-        BoxHelper.nativeCenter(xMin, yMin, xMax, yMax, out)
-
-    /**
-     * Return a copy of this object with modified values as provided, where [x1] and [y1] default to
-     * minimum values and [x2] and [y2] default to the maximum values, respectively.
-     */
-    @JvmSynthetic
-    public fun copy(
-        x1: Float = this.xMin,
-        y1: Float = this.yMin,
-        x2: Float = this.xMax,
-        y2: Float = this.yMax,
-    ): ImmutableBox =
-        if (this.xMin == x1 && this.yMin == y1 && this.xMax == x2 && this.yMax == y2) {
-            this
-        } else {
-            ImmutableBox(x1, y1, x2, y2)
-        }
-
     override fun equals(other: Any?): Boolean =
         other === this || (other is Box && Box.areEquivalent(this, other))
 
@@ -84,7 +55,7 @@
         /** Constructs an [ImmutableBox] with a given [center], [width], and [height]. */
         @JvmStatic
         public fun fromCenterAndDimensions(
-            center: Point,
+            center: Vec,
             @FloatRange(from = 0.0) width: Float,
             @FloatRange(from = 0.0) height: Float,
         ): ImmutableBox {
@@ -99,7 +70,7 @@
 
         /** Constructs the smallest [ImmutableBox] containing the two given points. */
         @JvmStatic
-        public fun fromTwoPoints(point1: Point, point2: Point): ImmutableBox {
+        public fun fromTwoPoints(point1: Vec, point2: Vec): ImmutableBox {
             return ImmutableBox(point1.x, point1.y, point2.x, point2.y)
         }
     }
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableParallelogram.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableParallelogram.kt
index 95ca1f7..6c2b5d8 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableParallelogram.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableParallelogram.kt
@@ -26,7 +26,7 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public class ImmutableParallelogram
 private constructor(
-    override val center: ImmutablePoint,
+    override val center: ImmutableVec,
     override val width: Float,
     override val height: Float,
     @AngleRadiansFloat override val rotation: Float,
@@ -50,7 +50,7 @@
          */
         @JvmStatic
         public fun fromCenterAndDimensions(
-            center: ImmutablePoint,
+            center: ImmutableVec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
         ): ImmutableParallelogram =
@@ -69,7 +69,7 @@
          */
         @JvmStatic
         public fun fromCenterDimensionsAndRotation(
-            center: ImmutablePoint,
+            center: ImmutableVec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
             @AngleRadiansFloat rotation: Float,
@@ -85,7 +85,7 @@
          */
         @JvmStatic
         public fun fromCenterDimensionsRotationAndShear(
-            center: ImmutablePoint,
+            center: ImmutableVec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
             @AngleRadiansFloat rotation: Float,
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutablePoint.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutablePoint.kt
deleted file mode 100644
index 44eb30c..0000000
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutablePoint.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import androidx.annotation.RestrictTo
-import kotlin.jvm.JvmSynthetic
-
-/** Represents a location in 2-dimensional space. See [MutablePoint] for a mutable alternative. */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
-public class ImmutablePoint(override val x: Float, override val y: Float) : Point {
-    /** Fills [output] with the x and y coordinates of this [ImmutablePoint] */
-    public fun fillMutable(output: MutablePoint) {
-        output.x = this.x
-        output.y = this.y
-    }
-
-    /** Returns a [MutablePoint] containing the same x and y coordinates as this [ImmutablePoint] */
-    public fun newMutable(): MutablePoint {
-        return MutablePoint(x, y)
-    }
-
-    /** Return a copy of this object with modified x and y as provided. */
-    @JvmSynthetic
-    public fun copy(x: Float = this.x, y: Float = this.y): ImmutablePoint =
-        if (x == this.x && y == this.y) this else ImmutablePoint(x, y)
-
-    override fun equals(other: Any?): Boolean =
-        other === this || (other is Point && Point.areEquivalent(this, other))
-
-    // NOMUTANTS -- not testing exact hashCode values, just that equality implies same hashCode
-    override fun hashCode(): Int = Point.hash(this)
-
-    override fun toString(): String = "Immutable${Point.string(this)}"
-}
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableVec.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableVec.kt
index fe0b830..b471711 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableVec.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ImmutableVec.kt
@@ -23,9 +23,13 @@
 import kotlin.math.sin
 
 /**
- * An immutable 2-dimensional vector, representing an offset in space. See [MutableVec] for a
- * mutable alternative, and see [Point] (and its concrete implementations [ImmutablePoint] and
- * [MutablePoint]) for a location in space.
+ * An immutable two-dimensional vector, i.e. an (x, y) coordinate pair. It can be used to represent
+ * either:
+ * 1) A two-dimensional offset, i.e. the difference between two points
+ * 2) A point in space, i.e. treating the vector as an offset from the origin
+ *
+ * This object is immutable, so it is inherently thread-safe. See [MutableVec] for a mutable
+ * alternative.
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public class ImmutableVec(override val x: Float, override val y: Float) : Vec {
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Intersection.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Intersection.kt
index ce3fce9..3b1160c 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Intersection.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Intersection.kt
@@ -117,7 +117,7 @@
      * intersection of the point in [mesh]’s object coordinates.
      */
     @JvmStatic
-    public fun Vec.intersects(mesh: ModeledShape, meshToPoint: AffineTransform): Boolean {
+    public fun Vec.intersects(mesh: PartitionedMesh, meshToPoint: AffineTransform): Boolean {
         return nativeMeshVecIntersects(
             nativeMeshAddress = mesh.getNativeAddress(),
             vecX = this.x,
@@ -218,7 +218,7 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun Segment.intersects(mesh: ModeledShape, meshToSegment: AffineTransform): Boolean {
+    public fun Segment.intersects(mesh: PartitionedMesh, meshToSegment: AffineTransform): Boolean {
         return nativeMeshSegmentIntersects(
             nativeMeshAddress = mesh.getNativeAddress(),
             segmentStartX = this.start.x,
@@ -310,7 +310,10 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun Triangle.intersects(mesh: ModeledShape, meshToTriangle: AffineTransform): Boolean {
+    public fun Triangle.intersects(
+        mesh: PartitionedMesh,
+        meshToTriangle: AffineTransform
+    ): Boolean {
         return nativeMeshTriangleIntersects(
             nativeMeshAddress = mesh.getNativeAddress(),
             triangleP0X = this.p0.x,
@@ -377,7 +380,7 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun Box.intersects(mesh: ModeledShape, meshToBox: AffineTransform): Boolean {
+    public fun Box.intersects(mesh: PartitionedMesh, meshToBox: AffineTransform): Boolean {
         return nativeMeshBoxIntersects(
             nativeMeshAddress = mesh.getNativeAddress(),
             boxXMin = this.xMin,
@@ -431,7 +434,7 @@
      */
     @JvmStatic
     public fun Parallelogram.intersects(
-        mesh: ModeledShape,
+        mesh: PartitionedMesh,
         meshToParallelogram: AffineTransform,
     ): Boolean {
         return nativeMeshParallelogramIntersects(
@@ -460,8 +463,8 @@
      * coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(
-        other: ModeledShape,
+    public fun PartitionedMesh.intersects(
+        other: PartitionedMesh,
         thisToCommonTransForm: AffineTransform,
         otherToCommonTransform: AffineTransform,
     ): Boolean {
@@ -558,7 +561,7 @@
      * intersection of the point in [mesh]’s object coordinates.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(point: Vec, meshToPoint: AffineTransform): Boolean =
+    public fun PartitionedMesh.intersects(point: Vec, meshToPoint: AffineTransform): Boolean =
         point.intersects(this, meshToPoint)
 
     /**
@@ -569,8 +572,10 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(segment: Segment, meshToSegment: AffineTransform): Boolean =
-        segment.intersects(this, meshToSegment)
+    public fun PartitionedMesh.intersects(
+        segment: Segment,
+        meshToSegment: AffineTransform
+    ): Boolean = segment.intersects(this, meshToSegment)
 
     /**
      * Returns true when a [PartitionedMesh] intersects with a [Triangle].
@@ -580,9 +585,9 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(
+    public fun PartitionedMesh.intersects(
         triangle: Triangle,
-        meshToTriangle: AffineTransform
+        meshToTriangle: AffineTransform,
     ): Boolean = triangle.intersects(this, meshToTriangle)
 
     /**
@@ -593,7 +598,7 @@
      * coordinate space to the coordinate space that the intersection should be checked in.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(box: Box, meshToBox: AffineTransform): Boolean =
+    public fun PartitionedMesh.intersects(box: Box, meshToBox: AffineTransform): Boolean =
         box.intersects(this, meshToBox)
 
     /**
@@ -605,7 +610,7 @@
      * checked in.
      */
     @JvmStatic
-    public fun ModeledShape.intersects(
+    public fun PartitionedMesh.intersects(
         parallelogram: Parallelogram,
         meshToParallelogram: AffineTransform,
     ): Boolean = parallelogram.intersects(this, meshToParallelogram)
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Mesh.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Mesh.kt
index 5c3e74f..e3959af 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Mesh.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Mesh.kt
@@ -135,7 +135,7 @@
      * [vertexCount]). The resulting x/y position of that vertex will be put into [outPosition],
      * which can be pre-allocated and reused to avoid allocations where appropriate.
      */
-    public fun fillPosition(@IntRange(from = 0) vertexIndex: Int, outPosition: MutablePoint) {
+    public fun fillPosition(@IntRange(from = 0) vertexIndex: Int, outPosition: MutableVec) {
         require(vertexIndex >= 0 && vertexIndex < vertexCount) {
             "vertexIndex=$vertexIndex must be between 0 and vertexCount=$vertexCount."
         }
@@ -239,7 +239,7 @@
     external fun fillPosition(
         nativeAddress: Long,
         vertexIndex: Int,
-        outPosition: MutablePoint
+        outPosition: MutableVec
     ) // TODO: b/355248266 - @Keep must go in Proguard config file instead.
 
     @VisibleForTesting
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableBox.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableBox.kt
index 9a417da..f6989d7 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableBox.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableBox.kt
@@ -47,10 +47,6 @@
     override var yMax: Float = max(y1, y2)
         private set
 
-    /** Populates [out] with the center of the [MutableBox]. */
-    override fun center(out: MutablePoint): Unit =
-        BoxHelper.nativeCenter(xMin, yMin, xMax, yMax, out)
-
     /**
      * Sets the lower and upper bounds in the `X` direction to new values. The minimum value becomes
      * `xMin`, and the maximum value becomes `xMax`. Returns the same instance to chain function
@@ -80,7 +76,7 @@
     public constructor() : this(0f, 0f, 0f, 0f)
 
     /** Constructs the smallest [MutableBox] containing the two given points. */
-    public fun fillFromTwoPoints(point1: Point, point2: Point): MutableBox {
+    public fun populateFromTwoPoints(point1: Vec, point2: Vec): MutableBox {
         setXBounds(point1.x, point2.x)
         setYBounds(point1.y, point2.y)
         return this
@@ -90,8 +86,8 @@
      * Constructs a [MutableBox] with a given [center], [width], and [height]. [width] and [height]
      * must be non-negative numbers.
      */
-    public fun fillFromCenterAndDimensions(
-        center: Point,
+    public fun populateFromCenterAndDimensions(
+        center: Vec,
         @FloatRange(from = 0.0) width: Float,
         @FloatRange(from = 0.0) height: Float,
     ): MutableBox {
@@ -110,16 +106,6 @@
         return this
     }
 
-    /** Convert this object to a new immutable [Box]. */
-    public fun buildBox(): ImmutableBox {
-        return ImmutableBox.fromTwoPoints(ImmutablePoint(xMin, yMin), ImmutablePoint(xMax, yMax))
-    }
-
-    /** Return a copy of this object that can be modified independently. */
-    public fun copy(): MutableBox {
-        return MutableBox(xMin, yMin, xMax, yMax)
-    }
-
     override fun equals(other: Any?): Boolean =
         other === this || (other is Box && Box.areEquivalent(this, other))
 
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableParallelogram.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableParallelogram.kt
index e899efa..42452ef 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableParallelogram.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableParallelogram.kt
@@ -26,7 +26,7 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public class MutableParallelogram
 private constructor(
-    center: Point,
+    center: Vec,
     width: Float,
     override var height: Float,
     @AngleRadiansFloat rotation: Float,
@@ -35,7 +35,7 @@
 
     /* [_center] is a private backing field that is internally constructed such that no
      * caller can obtain a direct reference to it. */
-    private var _center: MutablePoint = MutablePoint(center.x, center.y)
+    private var _center: MutableVec = MutableVec(center.x, center.y)
     @AngleRadiansFloat private var _rotation: Float = Angle.normalized(rotation)
     override var rotation: Float
         @AngleRadiansFloat get() = _rotation
@@ -43,7 +43,7 @@
             _rotation = Angle.normalized(value)
         }
 
-    override var center: Point
+    override var center: Vec
         get() = _center
         set(value) {
             _center.x = value.x
@@ -65,7 +65,7 @@
             }
         }
 
-    public constructor() : this(ImmutablePoint(0f, 0f), 0f, 0f, Angle.ZERO, 0f)
+    public constructor() : this(ImmutableVec(0f, 0f), 0f, 0f, Angle.ZERO, 0f)
 
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     // TODO: b/355248266 - @UsedByNative("parallelogram_jni_helper.cc") must go in Proguard config
@@ -106,7 +106,7 @@
          */
         @JvmStatic
         public fun fromCenterAndDimensions(
-            center: Point,
+            center: Vec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
         ): MutableParallelogram =
@@ -125,7 +125,7 @@
          */
         @JvmStatic
         public fun fromCenterDimensionsAndRotation(
-            center: Point,
+            center: Vec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
             @AngleRadiansFloat rotation: Float,
@@ -141,7 +141,7 @@
          */
         @JvmStatic
         public fun fromCenterDimensionsRotationAndShear(
-            center: Point,
+            center: Vec,
             @FloatRange(from = 0.0) width: Float,
             height: Float,
             @AngleRadiansFloat rotation: Float,
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutablePoint.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutablePoint.kt
deleted file mode 100644
index 8308e1b..0000000
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutablePoint.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import androidx.annotation.RestrictTo
-
-/**
- * Represents a location in 2-dimensional space. See [ImmutablePoint] for an immutable alternative.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
-public class MutablePoint(
-    override var x:
-        Float, // TODO: b/355248266 - @set:UsedByNative("point_jni_helper.cc") must go in Proguard
-    // config file instead.
-    override var y:
-        Float, // TODO: b/355248266 - @set:UsedByNative("point_jni_helper.cc") must go in Proguard
-    // config file instead.
-) : Point {
-
-    /**
-     * Constructs a [MutablePoint] without any initial data. This is useful when pre-allocating an
-     * instance to be filled later.
-     */
-    public constructor() : this(0f, 0f)
-
-    /** Construct an [ImmutablePoint] out of this [MutablePoint]. */
-    public fun build(): ImmutablePoint = ImmutablePoint(x, y)
-
-    override fun equals(other: Any?): Boolean =
-        other === this || (other is Point && Point.areEquivalent(this, other))
-
-    // NOMUTANTS -- not testing exact hashCode values, just that equality implies same hashCode
-    override fun hashCode(): Int = Point.hash(this)
-
-    override fun toString(): String = "Mutable${Point.string(this)}"
-}
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableVec.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableVec.kt
index e1d3d7a..e461aaf 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableVec.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/MutableVec.kt
@@ -23,18 +23,23 @@
 import kotlin.math.sin
 
 /**
- * A mutable 2-dimensional vector, representing an offset in space. See [ImmutableVec] for an
- * immutable alternative, and see [Point] (and its concrete implementations [ImmutablePoint] and
- * [MutablePoint]) for a location in space.
+ * A mutable two-dimensional vector, i.e. an (x, y) coordinate pair. It can be used to represent
+ * either:
+ * 1) A two-dimensional offset, i.e. the difference between two points
+ * 2) A point in space, i.e. treating the vector as an offset from the origin
+ *
+ * This object is mutable and is not inherently thread-safe, so callers should apply their own
+ * synchronization logic or use this object from a single thread. See [ImmutableVec] for an
+ * immutable alternative.
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public class MutableVec(
     override var x:
-        Float, // TODO: b/355248266 - @set:UsedByNative("vec_jni.cc") must go in Proguard config
-    // file instead.
+        Float, // TODO: b/355248266 - @set:UsedByNative("vec_jni_helper.cc") must go in Proguard
+    // config file instead.
     override var y:
-        Float, // TODO: b/355248266 - @set:UsedByNative("vec_jni.cc") must go in Proguard config
-    // file instead.
+        Float, // TODO: b/355248266 - @set:UsedByNative("vec_jni_helper.cc") must go in Proguard
+    // config file instead.
 ) : Vec {
 
     /**
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Parallelogram.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Parallelogram.kt
index eb09035..db1f6f4 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Parallelogram.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Parallelogram.kt
@@ -83,7 +83,7 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public interface Parallelogram {
 
-    public val center: Point
+    public val center: Vec
 
     /**
      * A [Parallelogram] may *not* have a negative width. If an operation on a parallelogram would
@@ -140,7 +140,7 @@
          * [Parallelogram].
          */
         internal fun areEquivalent(first: Parallelogram, second: Parallelogram): Boolean =
-            Point.areEquivalent(first.center, second.center) &&
+            Vec.areEquivalent(first.center, second.center) &&
                 first.width == second.width &&
                 first.height == second.height &&
                 first.rotation == second.rotation &&
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ModeledShape.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/PartitionedMesh.kt
similarity index 78%
rename from ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ModeledShape.kt
rename to ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/PartitionedMesh.kt
index bd67136..3a0d515d 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/ModeledShape.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/PartitionedMesh.kt
@@ -16,6 +16,7 @@
 
 package androidx.ink.geometry
 
+import androidx.annotation.FloatRange
 import androidx.annotation.IntRange
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
@@ -24,54 +25,57 @@
 import androidx.ink.nativeloader.NativeLoader
 
 /**
- * A triangulated shape, consisting of zero or more non-empty [Mesh]es, which may be indexed for
- * faster geometric queries. These meshes are divided among zero or more "render groups"; all the
- * meshes in a render group must have the same [MeshFormat], and can thus be rendered together. A
- * [ModeledShape] also optionally carries one or more "outlines", which are (potentially incomplete)
- * traversals of the vertices in the meshes, which could be used e.g. for path-based rendering. Note
- * that these render groups and outlines are ignored for the purposes of geometric queries; they
- * exist only for rendering purposes.
+ * An immutable† complex shape expressed as a set of triangles. This is used to represent the shape
+ * of a stroke or other complex objects see [MeshCreation]. The mesh may be divided into multiple
+ * partitions, which enables certain brush effects (e.g. "multi-coat"), and allows ink to create
+ * strokes requiring greater than 216 triangles (which must be rendered in multiple passes).
  *
- * This is not meant to be constructed directly by developers. The primary constructor is to have a
- * new instance of this class manage a native `ink::ModeledShape` instance created by another
- * Strokes API utility.
+ * A PartitionedMesh may optionally have one or more "outlines", which are polylines that traverse
+ * some or all of the vertices in the mesh; these are used for path-based rendering of strokes. This
+ * supports disjoint meshes such as dashed lines.
+ *
+ * PartitionedMesh provides fast intersection and coverage testing by use of an internal spatial
+ * index.
+ *
+ * † PartitionedMesh is technically not immutable, as the spatial index is lazily instantiated;
+ * however, from the perspective of a caller, its properties do not change over the course of its
+ * lifetime. The entire object is thread-safe.
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 @Suppress("NotCloseable") // Finalize is only used to free the native peer.
-public class ModeledShape
-/** Only for use within the ink library. Constructs a [ModeledShape] from native pointer. */
+public class PartitionedMesh
+/** Only for use within the ink library. Constructs a [PartitionedMesh] from native pointer. */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public constructor(
     /**
      * This is the raw pointer address of an `ink::ModeledShape` that has been heap allocated to be
-     * owned solely by this JVM [ModeledShape] object. Although the `ink::ModeledShape` is owned
-     * exclusively by this [ModeledShape] object, it may be a copy of another `ink::ModeledShape`,
-     * where it has a copy of fairly lightweight metadata but shares ownership of the more
-     * heavyweight `ink::Mesh` objects. This class is responsible for freeing the
+     * owned solely by this JVM [PartitionedMesh] object. Although the `ink::ModeledShape` is owned
+     * exclusively by this [PartitionedMesh] object, it may be a copy of another
+     * `ink::ModeledShape`, where it has a copy of fairly lightweight metadata but shares ownership
+     * of the more heavyweight `ink::Mesh` objects. This class is responsible for freeing the
      * `ink::ModeledShape` through its [finalize] method.
      */
     private var nativeAddress: Long
 ) {
 
     /**
-     * Only for use within the ink library. Returns the native pointer held by this [ModeledShape].
+     * Only for use within the ink library. Returns the native pointer held by this
+     * [PartitionedMesh].
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public fun getNativeAddress(): Long = nativeAddress
 
     private val scratchIntArray by threadLocal { IntArray(2) }
 
     /**
-     * Only for tests - creates a new empty [ModeledShape]. Since a [ModeledShape] is immutable,
-     * this serves no practical purpose outside of tests.
+     * Only for tests - creates a new empty [PartitionedMesh]. Since a [PartitionedMesh] is
+     * immutable, this serves no practical purpose outside of tests.
      */
     @VisibleForTesting internal constructor() : this(ModeledShapeNative.alloc())
 
     /**
-     * Returns the number of render groups in this shape. Each mesh in the [ModeledShape] belongs to
-     * exactly one render group, and all meshes in the same render group will have the same
-     * [MeshFormat] (and can thus be rendered together). The render groups are numbered in z-order
-     * (the group with index zero should be rendered on bottom; the group with the highest index
-     * should be rendered on top).
+     * The number of render groups in this mesh. Each outline in the [PartitionedMesh] belongs to
+     * exactly one render group, which are numbered in z-order: the group with index zero should be
+     * rendered on bottom; the group with the highest index should be rendered on top.
      */
     @IntRange(from = 0)
     public val renderGroupCount: Int =
@@ -86,7 +90,10 @@
         }
     }
 
-    /** The axis-aligned, rectangular region occupied by the [meshes] of this shape. */
+    /**
+     * The minimum bounding box of the [PartitionedMesh]. This will be null if the [PartitionedMesh]
+     * is empty.
+     */
     public val bounds: Box? = run {
         val envelope = BoxAccumulator()
         for (meshes in meshesByGroup) {
@@ -128,8 +135,8 @@
     }
 
     /**
-     * The number of vertices in the outline at index [outlineIndex], which can be up to (but not
-     * including) [outlineCount].
+     * The number of vertices that are in the outline at index [outlineIndex], and within the render
+     * group at [groupIndex].
      */
     @IntRange(from = 0)
     public fun outlineVertexCount(
@@ -150,11 +157,11 @@
      * [outlineVertexCount] with [outlineIndex]). The resulting x/y position of that outline vertex
      * will be put into [outPosition], which can be pre-allocated and reused to avoid allocations.
      */
-    public fun fillOutlinePosition(
+    public fun populateOutlinePosition(
         @IntRange(from = 0) groupIndex: Int,
         @IntRange(from = 0) outlineIndex: Int,
         @IntRange(from = 0) outlineVertexIndex: Int,
-        outPosition: MutablePoint,
+        outPosition: MutableVec,
     ) {
         val outlineVertexCount = outlineVertexCount(groupIndex, outlineIndex)
         require(outlineVertexIndex >= 0 && outlineVertexIndex < outlineVertexCount) {
@@ -173,27 +180,24 @@
         mesh.fillPosition(meshVertexIndex, outPosition)
     }
 
-    override fun toString(): String {
-        val address = java.lang.Long.toHexString(nativeAddress)
-        return "ModeledShape(bounds=$bounds, meshesByGroup=$meshesByGroup, nativeAddress=$address)"
-    }
-
     /**
-     * Computes an approximate measure of what portion of this [ModeledShape] is covered by or
+     * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or
      * overlaps with [triangle]. This is calculated by finding the sum of areas of the triangles
      * that intersect the given [triangle], and dividing that by the sum of the areas of all
-     * triangles in the [ModeledShape], all in the [ModeledShape]'s coordinate space. Triangles in
-     * the [ModeledShape] that overlap each other (e.g. in the case of a stroke that loops back over
-     * itself) are counted individually. Note that, if any triangles have negative area (due to
-     * winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute value of their
-     * area will be used instead.
+     * triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space.
+     * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that
+     * loops back over itself) are counted individually. Note that, if any triangles have negative
+     * area (due to winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute
+     * value of their area will be used instead.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [triangleToThis] contains the transform that maps from [triangle]'s
-     * coordinate space to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to the
+     * [IDENTITY].
      */
     @JvmOverloads
+    @FloatRange(from = 0.0, to = 1.0)
     public fun coverage(
         triangle: Triangle,
         triangleToThis: AffineTransform = AffineTransform.IDENTITY,
@@ -215,21 +219,22 @@
         )
 
     /**
-     * Computes an approximate measure of what portion of this [ModeledShape] is covered by or
+     * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or
      * overlaps with [box]. This is calculated by finding the sum of areas of the triangles that
      * intersect the given [box], and dividing that by the sum of the areas of all triangles in the
-     * [ModeledShape], all in the [ModeledShape]'s coordinate space. Triangles in the [ModeledShape]
-     * that overlap each other (e.g. in the case of a stroke that loops back over itself) are
-     * counted individually. Note that, if any triangles have negative area (due to winding, see
-     * [com.google.inputmethod.ink.Triangle.signedArea]), the absolute value of their area will be
-     * used instead.
+     * [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space. Triangles in the
+     * [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that loops back over
+     * itself) are counted individually. Note that, if any triangles have negative area (due to
+     * winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute value of their
+     * area will be used instead.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [boxToThis] contains the transform that maps from [box]'s coordinate space
-     * to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * to this [PartitionedMesh]'s coordinate space, which defaults to the [IDENTITY].
      */
     @JvmOverloads
+    @FloatRange(from = 0.0, to = 1.0)
     public fun coverage(box: Box, boxToThis: AffineTransform = AffineTransform.IDENTITY): Float =
         ModeledShapeNative.modeledShapeBoxCoverage(
             nativeAddress = nativeAddress,
@@ -246,22 +251,23 @@
         )
 
     /**
-     * Computes an approximate measure of what portion of this [ModeledShape] is covered by or
+     * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or
      * overlaps with [parallelogram]. This is calculated by finding the sum of areas of the
      * triangles that intersect the given [parallelogram], and dividing that by the sum of the areas
-     * of all triangles in the [ModeledShape], all in the [ModeledShape]'s coordinate space.
-     * Triangles in the [ModeledShape] that overlap each other (e.g. in the case of a stroke that
+     * of all triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space.
+     * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that
      * loops back over itself) are counted individually. Note that, if any triangles have negative
      * area (due to winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute
      * value of their area will be used instead.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [parallelogramToThis] contains the transform that maps from
-     * [parallelogram]'s coordinate space to this [ModeledShape]'s coordinate space, which defaults
-     * to the [IDENTITY].
+     * [parallelogram]'s coordinate space to this [PartitionedMesh]'s coordinate space, which
+     * defaults to the [IDENTITY].
      */
     @JvmOverloads
+    @FloatRange(from = 0.0, to = 1.0)
     public fun coverage(
         parallelogram: Parallelogram,
         parallelogramToThis: AffineTransform = AffineTransform.IDENTITY,
@@ -283,23 +289,25 @@
         )
 
     /**
-     * Computes an approximate measure of what portion of this [ModeledShape] is covered by or
-     * overlaps with the [other] [ModeledShape]. This is calculated by finding the sum of areas of
-     * the triangles that intersect [other], and dividing that by the sum of the areas of all
-     * triangles in the [ModeledShape], all in the [ModeledShape]'s coordinate space. Triangles in
-     * the [ModeledShape] that overlap each other (e.g. in the case of a stroke that loops back over
-     * itself) are counted individually. Note that, if any triangles have negative area (due to
-     * winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute value of their
-     * area will be used instead.
+     * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or
+     * overlaps with the [other] [PartitionedMesh]. This is calculated by finding the sum of areas
+     * of the triangles that intersect [other], and dividing that by the sum of the areas of all
+     * triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space.
+     * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that
+     * loops back over itself) are counted individually. Note that, if any triangles have negative
+     * area (due to winding, see [com.google.inputmethod.ink.Triangle.signedArea]), the absolute
+     * value of their area will be used instead.t
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [otherShapeToThis] contains the transform that maps from [other]'s
-     * coordinate space to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to the
+     * [IDENTITY].
      */
     @JvmOverloads
+    @FloatRange(from = 0.0, to = 1.0)
     public fun coverage(
-        other: ModeledShape,
+        other: PartitionedMesh,
         otherShapeToThis: AffineTransform = AffineTransform.IDENTITY,
     ): Float =
         ModeledShapeNative.modeledShapeModeledShapeCoverage(
@@ -314,7 +322,7 @@
         )
 
     /**
-     * Returns true if the approximate portion of the [ModeledShape] covered by [triangle] is
+     * Returns true if the approximate portion of the [PartitionedMesh] covered by [triangle] is
      * greater than [coverageThreshold].
      *
      * This is equivalent to:
@@ -324,10 +332,11 @@
      *
      * but may be faster.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [triangleToThis] contains the transform that maps from [triangle]'s
-     * coordinate space to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to the
+     * [IDENTITY].
      */
     @JvmOverloads
     public fun coverageIsGreaterThan(
@@ -353,7 +362,7 @@
         )
 
     /**
-     * Returns true if the approximate portion of the [ModeledShape] covered by [box] is greater
+     * Returns true if the approximate portion of the [PartitionedMesh] covered by [box] is greater
      * than [coverageThreshold].
      *
      * This is equivalent to:
@@ -363,10 +372,10 @@
      *
      * but may be faster.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [boxToThis] contains the transform that maps from [box]'s coordinate space
-     * to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * to this [PartitionedMesh]'s coordinate space, which defaults to the [IDENTITY].
      */
     @JvmOverloads
     public fun coverageIsGreaterThan(
@@ -390,8 +399,8 @@
         )
 
     /**
-     * Returns true if the approximate portion of the [ModeledShape] covered by [parallelogram] is
-     * greater than [coverageThreshold].
+     * Returns true if the approximate portion of the [PartitionedMesh] covered by [parallelogram]
+     * is greater than [coverageThreshold].
      *
      * This is equivalent to:
      * ```
@@ -400,11 +409,11 @@
      *
      * but may be faster.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [parallelogramToThis] contains the transform that maps from
-     * [parallelogram]'s coordinate space to this [ModeledShape]'s coordinate space, which defaults
-     * to the [IDENTITY].
+     * [parallelogram]'s coordinate space to this [PartitionedMesh]'s coordinate space, which
+     * defaults to the [IDENTITY].
      */
     @JvmOverloads
     public fun coverageIsGreaterThan(
@@ -430,8 +439,8 @@
         )
 
     /**
-     * Returns true if the approximate portion of this [ModeledShape] covered by the [other]
-     * [ModeledShape] is greater than [coverageThreshold].
+     * Returns true if the approximate portion of this [PartitionedMesh] covered by the [other]
+     * [PartitionedMesh] is greater than [coverageThreshold].
      *
      * This is equivalent to:
      * ```
@@ -440,14 +449,15 @@
      *
      * but may be faster.
      *
-     * On an empty [ModeledShape], this will always return 0.
+     * On an empty [PartitionedMesh], this will always return 0.
      *
      * Optional argument [otherShapeToThis] contains the transform that maps from [other]'s
-     * coordinate space to this [ModeledShape]'s coordinate space, which defaults to the [IDENTITY].
+     * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to the
+     * [IDENTITY].
      */
     @JvmOverloads
     public fun coverageIsGreaterThan(
-        other: ModeledShape,
+        other: PartitionedMesh,
         coverageThreshold: Float,
         otherShapeToThis: AffineTransform = AffineTransform.IDENTITY,
     ): Boolean =
@@ -472,9 +482,15 @@
         ModeledShapeNative.initializeSpatialIndex(nativeAddress)
 
     /** Returns true if this MutableEnvelope's spatial index has been initialized. */
-    public fun isSpatialIndexInitialized(): Boolean =
+    @VisibleForTesting
+    internal fun isSpatialIndexInitialized(): Boolean =
         ModeledShapeNative.isSpatialIndexInitialized(nativeAddress)
 
+    override fun toString(): String {
+        val address = java.lang.Long.toHexString(nativeAddress)
+        return "PartitionedMesh(bounds=$bounds, meshesByGroup=$meshesByGroup, nativeAddress=$address)"
+    }
+
     protected fun finalize() {
         // NOMUTANTS--Not tested post garbage collection.
         if (nativeAddress == 0L) return
@@ -488,8 +504,8 @@
 
 /**
  * Helper object to contain native JNI calls. The alternative to this is putting the methods in
- * [ModeledShape] itself (passes down an unused `jobject`, and doesn't work for native calls used by
- * constructors), or in [ModeledShape.Companion] (makes the `JNI_METHOD` naming less clear).
+ * [PartitionedMesh] itself (passes down an unused `jobject`, and doesn't work for native calls used
+ * by constructors), or in [PartitionedMesh.Companion] (makes the `JNI_METHOD` naming less clear).
  */
 private object ModeledShapeNative {
 
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Point.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Point.kt
deleted file mode 100644
index ce53d31..0000000
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Point.kt
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import androidx.annotation.FloatRange
-import androidx.annotation.RestrictTo
-import kotlin.math.abs
-
-/**
- * Represents a location in 2-dimensional space. See [ImmutablePoint] and [MutablePoint] for
- * concrete classes implementing [Point].
- *
- * The [Point] interface is the read-only view of the underlying data which may or may not be
- * mutable. Use the following concrete classes depending on the application requirement:
- *
- * For the [ImmutablePoint], the underlying data like the [x] and [y] coordinates is set once during
- * construction and does not change afterwards. Use this class for a simple [Point] that is
- * inherently thread-safe because of its immutability. A different value of an immutable object can
- * only be obtained by allocating a new one, and allocations can be expensive due to the risk of
- * garbage collection.
- *
- * For the [MutablePoint], the underlying data might change (e.g. by writing the [x] property). Use
- * this class to hold transient data in a performance critical situation, such as the input or
- * render path --- allocate the underlying [MutablePoint] once, perform operations on it and
- * overwrite it with new data.
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
-public interface Point {
-    /** The x-coordinate of the [Point] */
-    public val x: Float
-
-    /** The y-coordinate of the [Point] */
-    public val y: Float
-
-    /** Fills the x and y values of [output] with the x and y coordinates of this [Point] */
-    public fun getVec(output: MutableVec) {
-        output.x = this.x
-        output.y = this.y
-    }
-
-    /**
-     * Compares this [Point] with [other], and returns true if the difference between [x] and
-     * [other.x] is less than [tolerance], and likewise for [y].
-     */
-    public fun isAlmostEqual(
-        other: Point,
-        @FloatRange(from = 0.0) tolerance: Float = 0.0001f,
-    ): Boolean = (abs(x - other.x) < tolerance) && (abs(y - other.y) < tolerance)
-
-    public companion object {
-        /**
-         * Adds the x and y values of [lhs] to the x and y values of [rhs] and stores the result in
-         * [output].
-         */
-        @JvmStatic
-        public fun add(lhs: Point, rhs: Vec, output: MutablePoint) {
-            output.x = lhs.x + rhs.x
-            output.y = lhs.y + rhs.y
-        }
-
-        /**
-         * Adds the x and y values of [lhs] to the x and y values of [rhs] and stores the result in
-         * [output].
-         */
-        @JvmStatic
-        public fun add(lhs: Vec, rhs: Point, output: MutablePoint) {
-            output.x = lhs.x + rhs.x
-            output.y = lhs.y + rhs.y
-        }
-
-        /**
-         * Subtracts the x and y values of [rhs] from the x and y values of [lhs] and stores the
-         * result in [output].
-         */
-        @JvmStatic
-        public fun subtract(lhs: Point, rhs: Vec, output: MutablePoint) {
-            output.x = lhs.x - rhs.x
-            output.y = lhs.y - rhs.y
-        }
-
-        /**
-         * Subtracts the x and y values of [rhs] from the x and y values of [lhs] and stores the
-         * result in [output].
-         */
-        @JvmStatic
-        public fun subtract(lhs: Point, rhs: Point, output: MutableVec) {
-            output.x = lhs.x - rhs.x
-            output.y = lhs.y - rhs.y
-        }
-
-        /**
-         * Returns true if [first] and [second] have the same values for all properties of [Point].
-         */
-        internal fun areEquivalent(first: Point, second: Point): Boolean {
-            return first.x == second.x && first.y == second.y
-        }
-
-        /** Returns a hash code for [point] using its [Point] properties. */
-        internal fun hash(point: Point): Int = 31 * point.x.hashCode() + point.y.hashCode()
-
-        /** Returns a string representation for [point] using its [Point] properties. */
-        internal fun string(point: Point): String = "Point(x=${point.x}, y=${point.y})"
-    }
-}
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Segment.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Segment.kt
index fa6d373..d53354d 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Segment.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Segment.kt
@@ -59,7 +59,7 @@
         get() = run {
             // TODO(b/354236964): Optimize unnecessary allocations
             val (minX, maxX, minY, maxY) = getBoundingXYCoordinates(this)
-            ImmutableBox.fromTwoPoints(ImmutablePoint(minX, minY), ImmutablePoint(maxX, maxY))
+            ImmutableBox.fromTwoPoints(ImmutableVec(minX, minY), ImmutableVec(maxX, maxY))
         }
 
     /** Populates [output] with the minimum bounding box containing the [Segment]. */
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Triangle.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Triangle.kt
index ee975b2..2a0128a 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Triangle.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Triangle.kt
@@ -54,7 +54,7 @@
         get() = run {
             // TODO(b/354236964): Optimize unnecessary allocations
             val (minX, maxX, minY, maxY) = getBoundingXYCoordinates(this)
-            ImmutableBox.fromTwoPoints(ImmutablePoint(minX, minY), ImmutablePoint(maxX, maxY))
+            ImmutableBox.fromTwoPoints(ImmutableVec(minX, minY), ImmutableVec(maxX, maxY))
         }
 
     /** Populates [output] with the minimum bounding box containing the [Triangle]. */
diff --git a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Vec.kt b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Vec.kt
index c02d918..549dfe8 100644
--- a/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Vec.kt
+++ b/ink/ink-geometry/src/jvmAndroidMain/kotlin/androidx/ink/geometry/Vec.kt
@@ -22,9 +22,9 @@
 import kotlin.math.atan2
 
 /**
- * A 2-dimensional vector, representing an offset in space. See [MutableVec] for a mutable, and
- * [ImmutableVec] for an immutable implementation of [Vec]. See [Point] (and its concrete
- * implementations [ImmutablePoint] and [MutablePoint]) for a location in space.
+ * A two-dimensional vector, i.e. an (x, y) coordinate pair. It can be used to represent either:
+ * 1) A two-dimensional offset, i.e. the difference between two points
+ * 2) A point in space, i.e. treating the vector as an offset from the origin
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // PublicApiNotReadyForJetpackReview
 public interface Vec {
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxAccumulatorTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxAccumulatorTest.kt
index 6751546..fd7ee5b 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxAccumulatorTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxAccumulatorTest.kt
@@ -77,7 +77,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(0.1F, 2F), ImmutablePoint(3F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(0.1F, 2F), ImmutableVec(3F, 4F))
                     )
             )
     }
@@ -93,7 +93,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 1.2F), ImmutablePoint(3F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 1.2F), ImmutableVec(3F, 4F))
                     )
             )
     }
@@ -109,7 +109,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3.1F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3.1F, 4F))
                     )
             )
     }
@@ -125,7 +125,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4.2F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4.2F))
                     )
             )
     }
@@ -143,7 +143,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 1F), ImmutablePoint(4F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 1F), ImmutableVec(4F, 4F))
                     )
             )
     }
@@ -172,7 +172,7 @@
 
         envelope.add(
             BoxAccumulator(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(1.1F, 2.1F), ImmutablePoint(2.9F, 3.9F))
+                ImmutableBox.fromTwoPoints(ImmutableVec(1.1F, 2.1F), ImmutableVec(2.9F, 3.9F))
             )
         )
 
@@ -185,7 +185,7 @@
 
         envelope.add(
             BoxAccumulator(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(0.9F, 1.9F), ImmutablePoint(3.1F, 4.1F))
+                ImmutableBox.fromTwoPoints(ImmutableVec(0.9F, 1.9F), ImmutableVec(3.1F, 4.1F))
             )
         )
 
@@ -194,9 +194,9 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(
-                                ImmutablePoint(0.9F, 1.9F),
-                                ImmutablePoint(3.1F, 4.1F)
+                            .populateFromTwoPoints(
+                                ImmutableVec(0.9F, 1.9F),
+                                ImmutableVec(3.1F, 4.1F)
                             )
                     )
             )
@@ -206,12 +206,10 @@
     fun addEnvelope_whenNewAndCurrentOverlap_shouldUpdateToUnion() {
         val envelope =
             BoxAccumulator()
-                .add(MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 8F), ImmutablePoint(4F, 9F)))
+                .add(MutableBox().populateFromTwoPoints(ImmutableVec(1F, 8F), ImmutableVec(4F, 9F)))
 
         envelope.add(
-            BoxAccumulator(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(2F, 7F), ImmutablePoint(3F, 10F))
-            )
+            BoxAccumulator(ImmutableBox.fromTwoPoints(ImmutableVec(2F, 7F), ImmutableVec(3F, 10F)))
         )
 
         assertThat(envelope)
@@ -219,7 +217,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 7F), ImmutablePoint(4F, 10F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 7F), ImmutableVec(4F, 10F))
                     )
             )
     }
@@ -229,9 +227,7 @@
         val envelope = BoxAccumulator().add(rect1234)
 
         envelope.add(
-            BoxAccumulator(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(2F, 0F), ImmutablePoint(5F, 1F))
-            )
+            BoxAccumulator(ImmutableBox.fromTwoPoints(ImmutableVec(2F, 0F), ImmutableVec(5F, 1F)))
         )
 
         assertThat(envelope)
@@ -239,7 +235,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 0F), ImmutablePoint(5F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 0F), ImmutableVec(5F, 4F))
                     )
             )
     }
@@ -251,7 +247,7 @@
 
     @Test
     fun rect_withBounds_returnsBox() {
-        val addition = rect1234.newMutable()
+        val addition = MutableBox().populateFrom(rect1234)
         val envelope = BoxAccumulator().add(addition)
 
         val rect = envelope.box
@@ -285,7 +281,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 10F), ImmutablePoint(3F, 15F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 10F), ImmutableVec(3F, 15F))
                     )
             )
     }
@@ -296,7 +292,7 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
         val segment = ImmutableSegment(start = ImmutableVec(1f, 10f), end = ImmutableVec(30f, 150f))
 
@@ -308,7 +304,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 10F), ImmutablePoint(30F, 150F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 10F), ImmutableVec(30F, 150F))
                     )
             )
     }
@@ -331,7 +327,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 5F), ImmutablePoint(10F, 20F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 5F), ImmutableVec(10F, 20F))
                     )
             )
     }
@@ -342,7 +338,7 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
         val triangle =
             ImmutableTriangle(
@@ -359,7 +355,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 5F), ImmutablePoint(20F, 25F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 5F), ImmutableVec(20F, 25F))
                     )
             )
     }
@@ -367,7 +363,7 @@
     @Test
     fun add_rectToEmptyEnvelope_updatesEnvelope() {
         val envelope = BoxAccumulator()
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 10f), ImmutablePoint(-3f, -20f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(1f, 10f), ImmutableVec(-3f, -20f))
 
         envelope.add(rect)
 
@@ -377,7 +373,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(-3F, -20F), ImmutablePoint(1F, 10F))
+                            .populateFromTwoPoints(ImmutableVec(-3F, -20F), ImmutableVec(1F, 10F))
                     )
             )
     }
@@ -388,10 +384,9 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
-        val rect =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(100f, 200f), ImmutablePoint(300f, 400f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(100f, 200f), ImmutableVec(300f, 400f))
 
         envelope.add(rect)
 
@@ -401,7 +396,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(300F, 400F))
+                            .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(300F, 400F))
                     )
             )
     }
@@ -411,7 +406,7 @@
         val envelope = BoxAccumulator()
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(10f, 20f),
+                center = ImmutableVec(10f, 20f),
                 width = 4f,
                 height = 6f,
                 rotation = Angle.ZERO,
@@ -426,7 +421,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(8F, 17F), ImmutablePoint(12F, 23F))
+                            .populateFromTwoPoints(ImmutableVec(8F, 17F), ImmutableVec(12F, 23F))
                     )
             )
     }
@@ -437,11 +432,11 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
         val parallelogram =
             ImmutableParallelogram.fromCenterAndDimensions(
-                center = ImmutablePoint(100f, 200f),
+                center = ImmutableVec(100f, 200f),
                 width = 500f,
                 height = 1000f,
             )
@@ -454,9 +449,9 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(
-                                ImmutablePoint(-150F, -300F),
-                                ImmutablePoint(350F, 700F)
+                            .populateFromTwoPoints(
+                                ImmutableVec(-150F, -300F),
+                                ImmutableVec(350F, 700F)
                             )
                     )
             )
@@ -479,13 +474,13 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
         val secondEnvelope =
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(-150F, -300F), ImmutablePoint(350F, 700F))
+                        .populateFromTwoPoints(ImmutableVec(-150F, -300F), ImmutableVec(350F, 700F))
                 )
 
         envelope.add(secondEnvelope)
@@ -496,9 +491,9 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(
-                                ImmutablePoint(-150F, -300F),
-                                ImmutablePoint(350F, 700F)
+                            .populateFromTwoPoints(
+                                ImmutableVec(-150F, -300F),
+                                ImmutableVec(350F, 700F)
                             )
                     )
             )
@@ -517,7 +512,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 10F), ImmutablePoint(1F, 10F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 10F), ImmutableVec(1F, 10F))
                     )
             )
     }
@@ -528,7 +523,7 @@
             BoxAccumulator()
                 .add(
                     MutableBox()
-                        .fillFromTwoPoints(ImmutablePoint(10F, 10F), ImmutablePoint(20F, 25F))
+                        .populateFromTwoPoints(ImmutableVec(10F, 10F), ImmutableVec(20F, 25F))
                 )
         val point = MutableVec(1f, 5f)
 
@@ -540,7 +535,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(1F, 5F), ImmutablePoint(20F, 25F))
+                            .populateFromTwoPoints(ImmutableVec(1F, 5F), ImmutableVec(20F, 25F))
                     )
             )
     }
@@ -548,7 +543,7 @@
     @Test
     fun add_emptyMeshToEmptyEnvelope_doesNotUpdateEnvelope() {
         val envelope = BoxAccumulator()
-        val mesh = ModeledShape()
+        val mesh = PartitionedMesh()
 
         envelope.add(mesh)
 
@@ -580,8 +575,8 @@
             BoxAccumulator()
                 .add(
                     ImmutableBox.fromTwoPoints(
-                        ImmutablePoint(1.00001F, 2.00001F),
-                        ImmutablePoint(2.99999F, 3.99999F),
+                        ImmutableVec(1.00001F, 2.00001F),
+                        ImmutableVec(2.99999F, 3.99999F),
                     )
                 )
 
@@ -635,7 +630,7 @@
                 BoxAccumulator()
                     .add(
                         MutableBox()
-                            .fillFromTwoPoints(ImmutablePoint(2F, 2F), ImmutablePoint(3F, 4F))
+                            .populateFromTwoPoints(ImmutableVec(2F, 2F), ImmutableVec(3F, 4F))
                     )
             )
     }
@@ -669,8 +664,6 @@
         assertThat(string).contains("MutableBox")
     }
 
-    private val rect1234 =
-        ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-    private val rect5678 =
-        ImmutableBox.fromTwoPoints(ImmutablePoint(5F, 6F), ImmutablePoint(7F, 8F))
+    private val rect1234 = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
+    private val rect5678 = ImmutableBox.fromTwoPoints(ImmutableVec(5F, 6F), ImmutableVec(7F, 8F))
 }
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxTest.kt
index a6ba94b..74fc31d 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/BoxTest.kt
@@ -26,12 +26,12 @@
 
     @Test
     fun isAlmostEqual_withToleranceGiven_returnsCorrectValue() {
-        val box = ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 2f), ImmutablePoint(3f, 4f))
+        val box = ImmutableBox.fromTwoPoints(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f))
 
         assertThat(box.isAlmostEqual(box, tolerance = 0.00000001f)).isTrue()
         assertThat(
                 box.isAlmostEqual(
-                    ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 2f), ImmutablePoint(3f, 4f)),
+                    ImmutableBox.fromTwoPoints(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f)),
                     tolerance = 0.00000001f,
                 )
             )
@@ -39,8 +39,8 @@
         assertThat(
                 box.isAlmostEqual(
                     ImmutableBox.fromTwoPoints(
-                        ImmutablePoint(1.00001f, 1.99999f),
-                        ImmutablePoint(3f, 4f)
+                        ImmutableVec(1.00001f, 1.99999f),
+                        ImmutableVec(3f, 4f)
                     ),
                     tolerance = 0.000001f,
                 )
@@ -49,8 +49,8 @@
         assertThat(
                 box.isAlmostEqual(
                     ImmutableBox.fromTwoPoints(
-                        ImmutablePoint(1f, 2f),
-                        ImmutablePoint(3.00001f, 3.99999f)
+                        ImmutableVec(1f, 2f),
+                        ImmutableVec(3.00001f, 3.99999f)
                     ),
                     tolerance = 0.000001f,
                 )
@@ -58,14 +58,14 @@
             .isFalse()
         assertThat(
                 box.isAlmostEqual(
-                    ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 1.99f), ImmutablePoint(3f, 4f)),
+                    ImmutableBox.fromTwoPoints(ImmutableVec(1f, 1.99f), ImmutableVec(3f, 4f)),
                     tolerance = 0.02f,
                 )
             )
             .isTrue()
         assertThat(
                 box.isAlmostEqual(
-                    ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 2f), ImmutablePoint(3.01f, 4f)),
+                    ImmutableBox.fromTwoPoints(ImmutableVec(1f, 2f), ImmutableVec(3.01f, 4f)),
                     tolerance = 0.02f,
                 )
             )
@@ -74,11 +74,11 @@
 
     @Test
     fun isAlmostEqual_whenSameInterface_returnsTrue() {
-        val box = MutableBox().fillFromTwoPoints(ImmutablePoint(1f, 2f), ImmutablePoint(3f, 4f))
+        val box = MutableBox().populateFromTwoPoints(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f))
         val other =
             ImmutableBox.fromTwoPoints(
-                ImmutablePoint(0.99999f, 2.00001f),
-                ImmutablePoint(3.00001f, 3.99999f),
+                ImmutableVec(0.99999f, 2.00001f),
+                ImmutableVec(3.00001f, 3.99999f)
             )
         assertThat(box.isAlmostEqual(other, tolerance = 0.0001f)).isTrue()
     }
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableAffineTransformTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableAffineTransformTest.kt
index e498235..d0f5b7c 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableAffineTransformTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableAffineTransformTest.kt
@@ -370,26 +370,26 @@
 
     @Test
     fun applyTransform_whenAppliedToABox_correctlyModifiesParallelogram() {
-        val testBox = ImmutableBox.fromCenterAndDimensions(ImmutablePoint(4f, 1f), 6f, 8f)
+        val testBox = ImmutableBox.fromCenterAndDimensions(ImmutableVec(4f, 1f), 6f, 8f)
 
         val identityTransform = AffineTransform.IDENTITY
         val identityParallelogram = MutableParallelogram()
         identityTransform.applyTransform(testBox, identityParallelogram)
         assertThat(identityParallelogram)
-            .isEqualTo(MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(4f, 1f), 6f, 8f))
+            .isEqualTo(MutableParallelogram.fromCenterAndDimensions(ImmutableVec(4f, 1f), 6f, 8f))
 
         val translateTransform = ImmutableAffineTransform.translate(ImmutableVec(1F, 3F))
         val translateParallelogram = MutableParallelogram()
         translateTransform.applyTransform(testBox, translateParallelogram)
         assertThat(translateParallelogram)
-            .isEqualTo(MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(5f, 4f), 6f, 8f))
+            .isEqualTo(MutableParallelogram.fromCenterAndDimensions(ImmutableVec(5f, 4f), 6f, 8f))
 
         val scaleBy2ValuesTransform = ImmutableAffineTransform.scale(2.5F, -.5F)
         val scaleBy2ValuesParallelogram = MutableParallelogram()
         scaleBy2ValuesTransform.applyTransform(testBox, scaleBy2ValuesParallelogram)
         assertThat(scaleBy2ValuesParallelogram)
             .isEqualTo(
-                MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(10f, -0.5f), 15f, -4f)
+                MutableParallelogram.fromCenterAndDimensions(ImmutableVec(10f, -0.5f), 15f, -4f)
             )
 
         val scaleBy1ValueTransform = ImmutableAffineTransform.scale(2.5F)
@@ -397,23 +397,21 @@
         scaleBy1ValueTransform.applyTransform(testBox, scaleBy1ValueParallelogram)
         assertThat(scaleBy1ValueParallelogram)
             .isEqualTo(
-                MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(10f, 2.5f), 15f, 20f)
+                MutableParallelogram.fromCenterAndDimensions(ImmutableVec(10f, 2.5f), 15f, 20f)
             )
 
         val scaleXTransform = ImmutableAffineTransform.scaleX(2.5F)
         val scaleXParallelogram = MutableParallelogram()
         scaleXTransform.applyTransform(testBox, scaleXParallelogram)
         assertThat(scaleXParallelogram)
-            .isEqualTo(
-                MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(10f, 1f), 15f, 8f)
-            )
+            .isEqualTo(MutableParallelogram.fromCenterAndDimensions(ImmutableVec(10f, 1f), 15f, 8f))
 
         val scaleYTransform = ImmutableAffineTransform.scaleY(2.5F)
         val scaleYParallelogram = MutableParallelogram()
         scaleYTransform.applyTransform(testBox, scaleYParallelogram)
         assertThat(scaleYParallelogram)
             .isEqualTo(
-                MutableParallelogram.fromCenterAndDimensions(ImmutablePoint(4f, 2.5f), 6f, 20f)
+                MutableParallelogram.fromCenterAndDimensions(ImmutableVec(4f, 2.5f), 6f, 20f)
             )
 
         val shearXTransform = ImmutableAffineTransform(1f, 2.5F, 0f, 0f, 1f, 0f)
@@ -422,7 +420,7 @@
         assertThat(shearXParallelogram)
             .isEqualTo(
                 MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(6.5f, 1f),
+                    ImmutableVec(6.5f, 1f),
                     6f,
                     8f,
                     0.0f,
@@ -439,7 +437,7 @@
                 Parallelogram.areNear(
                     rotateParallelogram,
                     MutableParallelogram.fromCenterDimensionsAndRotation(
-                        ImmutablePoint(-4f, -1f),
+                        ImmutableVec(-4f, -1f),
                         6f,
                         8f,
                         Angle.HALF_TURN_RADIANS,
@@ -453,7 +451,7 @@
     fun applyTransform_whenAppliedToAParallelogram_correctlyModifiesParallelogram() {
         val testParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(4f, 1f),
+                ImmutableVec(4f, 1f),
                 6f,
                 8f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -466,7 +464,7 @@
         assertThat(identityParallelogram)
             .isEqualTo(
                 MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(4f, 1f),
+                    ImmutableVec(4f, 1f),
                     6f,
                     8f,
                     Angle.QUARTER_TURN_RADIANS,
@@ -480,7 +478,7 @@
         assertThat(translateParallelogram)
             .isEqualTo(
                 MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(5f, 4f),
+                    ImmutableVec(5f, 4f),
                     6f,
                     8f,
                     Angle.QUARTER_TURN_RADIANS,
@@ -495,7 +493,7 @@
                 Parallelogram.areNear(
                     scaleBy2ValuesParallelogram,
                     MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                        ImmutablePoint(10f, -0.5f),
+                        ImmutableVec(10f, -0.5f),
                         3f,
                         -20f,
                         Angle.QUARTER_TURN_RADIANS + Angle.HALF_TURN_RADIANS,
@@ -513,7 +511,7 @@
                 Parallelogram.areNear(
                     scaleBy1ValueParallelogram,
                     MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                        ImmutablePoint(10f, 2.5f),
+                        ImmutableVec(10f, 2.5f),
                         15f,
                         20f,
                         Angle.QUARTER_TURN_RADIANS,
@@ -531,7 +529,7 @@
                 Parallelogram.areNear(
                     scaleXParallelogram,
                     MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                        ImmutablePoint(10f, 1f),
+                        ImmutableVec(10f, 1f),
                         6f,
                         20f,
                         Angle.QUARTER_TURN_RADIANS,
@@ -549,7 +547,7 @@
                 Parallelogram.areNear(
                     scaleYParallelogram,
                     MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                        ImmutablePoint(4f, 2.5f),
+                        ImmutableVec(4f, 2.5f),
                         15f,
                         8f,
                         Angle.QUARTER_TURN_RADIANS,
@@ -569,7 +567,7 @@
                 Parallelogram.areNear(
                     rotateParallelogram,
                     MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                        ImmutablePoint(-4f, -1f),
+                        ImmutableVec(-4f, -1f),
                         6f,
                         8f,
                         Angle.HALF_TURN_RADIANS + Angle.QUARTER_TURN_RADIANS,
@@ -584,7 +582,7 @@
     fun applyTransform_whenAppliedToAMutableParallelogram_canModifyInputAsOutput() {
         val testMutableParallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(4f, 1f),
+                ImmutableVec(4f, 1f),
                 6f,
                 8f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -596,7 +594,7 @@
         assertThat(testMutableParallelogram)
             .isEqualTo(
                 MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(5f, 4f),
+                    ImmutableVec(5f, 4f),
                     6f,
                     8f,
                     Angle.QUARTER_TURN_RADIANS,
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableBoxTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableBoxTest.kt
index ccde8423..194b848 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableBoxTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableBoxTest.kt
@@ -26,7 +26,7 @@
 
     @Test
     fun fromCenterAndDimensions_constructsCorrectImmutableBox() {
-        val rect = ImmutableBox.fromCenterAndDimensions(ImmutablePoint(20f, -50f), 10f, 20f)
+        val rect = ImmutableBox.fromCenterAndDimensions(ImmutableVec(20f, -50f), 10f, 20f)
 
         assertThat(rect.xMin).isEqualTo(15f)
         assertThat(rect.xMax).isEqualTo(25f)
@@ -38,7 +38,7 @@
 
     @Test
     fun fromTwoPoints_constructsCorrectImmutableBox() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(20f, -50f), MutablePoint(-70f, 100f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(20f, -50f), MutableVec(-70f, 100f))
 
         assertThat(rect.xMin).isEqualTo(-70f)
         assertThat(rect.xMax).isEqualTo(20f)
@@ -50,7 +50,7 @@
 
     @Test
     fun minMaxFields_whenAllZeroes_allAreZero() {
-        val zeroes = ImmutableBox.fromTwoPoints(ImmutablePoint(0F, 0F), ImmutablePoint(0F, 0F))
+        val zeroes = ImmutableBox.fromTwoPoints(ImmutableVec(0F, 0F), ImmutableVec(0F, 0F))
         assertThat(zeroes.xMin).isEqualTo(0F)
         assertThat(zeroes.yMin).isEqualTo(0F)
         assertThat(zeroes.xMax).isEqualTo(0F)
@@ -59,7 +59,7 @@
 
     @Test
     fun minMaxFields_whenDeclaredInMinMaxOrder_matchOrder() {
-        val inOrder = ImmutableBox.fromTwoPoints(ImmutablePoint(-1F, -2F), ImmutablePoint(3F, 4F))
+        val inOrder = ImmutableBox.fromTwoPoints(ImmutableVec(-1F, -2F), ImmutableVec(3F, 4F))
         assertThat(inOrder.xMin).isEqualTo(-1F)
         assertThat(inOrder.yMin).isEqualTo(-2F)
         assertThat(inOrder.xMax).isEqualTo(3F)
@@ -68,8 +68,7 @@
 
     @Test
     fun minMaxFields_whenDeclaredOutOfOrder_doNotMatchOrder() {
-        val outOfOrder =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(-3F, -4F))
+        val outOfOrder = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(-3F, -4F))
         assertThat(outOfOrder.xMin).isEqualTo(-3F)
         assertThat(outOfOrder.yMin).isEqualTo(-4F)
         assertThat(outOfOrder.xMax).isEqualTo(1F)
@@ -78,7 +77,7 @@
 
     @Test
     fun widthHeight_whenAllZeroes_areAllZero() {
-        val zeroes = ImmutableBox.fromTwoPoints(ImmutablePoint(0F, 0F), ImmutablePoint(0F, 0F))
+        val zeroes = ImmutableBox.fromTwoPoints(ImmutableVec(0F, 0F), ImmutableVec(0F, 0F))
 
         assertThat(zeroes.width).isEqualTo(0)
         assertThat(zeroes.height).isEqualTo(0)
@@ -86,7 +85,7 @@
 
     @Test
     fun widthHeight_whenDeclaredInOrder_areCorrectValues() {
-        val inOrder = ImmutableBox.fromTwoPoints(ImmutablePoint(-1F, -2F), ImmutablePoint(3F, 4F))
+        val inOrder = ImmutableBox.fromTwoPoints(ImmutableVec(-1F, -2F), ImmutableVec(3F, 4F))
 
         assertThat(inOrder.width).isEqualTo(4F)
         assertThat(inOrder.height).isEqualTo(6F)
@@ -94,8 +93,7 @@
 
     @Test
     fun widthHeight_whenDeclaredOutOfOrder_areCorrectValues() {
-        val outOfOrder =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(-3F, -4F))
+        val outOfOrder = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(-3F, -4F))
 
         assertThat(outOfOrder.width).isEqualTo(4F)
         assertThat(outOfOrder.height).isEqualTo(6F)
@@ -103,8 +101,7 @@
 
     @Test
     fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox).isEqualTo(immutableBox)
         assertThat(immutableBox.hashCode()).isEqualTo(immutableBox.hashCode())
@@ -112,18 +109,17 @@
 
     @Test
     fun equals_whenDifferentType_returnsFalse() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
-        assertThat(immutableBox).isNotEqualTo(ImmutablePoint(1F, 2F))
+        assertThat(immutableBox).isNotEqualTo(ImmutableVec(1F, 2F))
     }
 
     @Test
     fun equals_whenSameInterfacePropertiesAndDifferentType_returnsTrue() {
-        val point1 = ImmutablePoint(1F, 2F)
-        val point2 = ImmutablePoint(3F, 4F)
+        val point1 = ImmutableVec(1F, 2F)
+        val point2 = ImmutableVec(3F, 4F)
         val immutableBox = ImmutableBox.fromTwoPoints(point1, point2)
-        val mutableBox = MutableBox().fillFromTwoPoints(point1, point2)
+        val mutableBox = MutableBox().populateFromTwoPoints(point1, point2)
 
         assertThat(immutableBox).isEqualTo(mutableBox)
         assertThat(immutableBox.hashCode()).isEqualTo(mutableBox.hashCode())
@@ -131,9 +127,8 @@
 
     @Test
     fun equals_whenSameValues_returnsTrueAndSameHashCode() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        val other = ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
+        val other = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox).isEqualTo(other)
         assertThat(immutableBox.hashCode()).isEqualTo(other.hashCode())
@@ -141,9 +136,8 @@
 
     @Test
     fun equals_whenSameValuesOutOfOrder_returnsTrueAndSameHashCode() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        val other = ImmutableBox.fromTwoPoints(ImmutablePoint(3F, 4F), ImmutablePoint(1F, 2F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
+        val other = ImmutableBox.fromTwoPoints(ImmutableVec(3F, 4F), ImmutableVec(1F, 2F))
 
         assertThat(immutableBox).isEqualTo(other)
         assertThat(immutableBox.hashCode()).isEqualTo(other.hashCode())
@@ -151,103 +145,65 @@
 
     @Test
     fun equals_whenDifferentXMin_returnsFalse() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox)
-            .isNotEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(-1F, 2F), ImmutablePoint(3F, 4F))
-            )
+            .isNotEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-1F, 2F), ImmutableVec(3F, 4F)))
     }
 
     @Test
     fun equals_whenDifferentYMin_returnsFalse() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox)
-            .isNotEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(1F, -2F), ImmutablePoint(3F, 4F))
-            )
+            .isNotEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(1F, -2F), ImmutableVec(3F, 4F)))
     }
 
     @Test
     fun equals_whenDifferentXMax_returnsFalse() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox)
-            .isNotEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(30F, 4F))
-            )
+            .isNotEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(30F, 4F)))
     }
 
     @Test
     fun equals_whenDifferentYMax_returnsFalse() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(immutableBox)
-            .isNotEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 40F))
-            )
+            .isNotEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 40F)))
     }
 
     @Test
-    fun newMutable_matchesValues() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+    fun populateCenter_modifiesMutablePoint() {
+        val immutableBox = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 20F), ImmutableVec(3F, 40F))
+        val outCenter = MutableVec()
+        immutableBox.populateCenter(outCenter)
 
-        assertThat(immutableBox.newMutable())
-            .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-            )
+        assertThat(outCenter).isEqualTo(MutableVec(2F, 30F))
     }
 
     @Test
-    fun fillMutable_correctlyModifiesOutput() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        val output = MutableBox()
-
-        immutableBox.fillMutable(output)
-
-        assertThat(output)
-            .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-            )
-    }
-
-    @Test
-    fun center_modifiesMutablePoint() {
-        val immutableBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 20F), ImmutablePoint(3F, 40F))
-        val outCenter = MutablePoint()
-        immutableBox.center(outCenter)
-
-        assertThat(outCenter).isEqualTo(MutablePoint(2F, 30F))
-    }
-
-    @Test
-    fun corners_modifiesMutablePoints() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 20F), ImmutablePoint(3F, 40F))
-        val p0 = MutablePoint()
-        val p1 = MutablePoint()
-        val p2 = MutablePoint()
-        val p3 = MutablePoint()
+    fun corners_modifiesMutableVecs() {
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 20F), ImmutableVec(3F, 40F))
+        val p0 = MutableVec()
+        val p1 = MutableVec()
+        val p2 = MutableVec()
+        val p3 = MutableVec()
         rect.corners(p0, p1, p2, p3)
 
-        assertThat(p0).isEqualTo(MutablePoint(1F, 20F))
-        assertThat(p1).isEqualTo(MutablePoint(3F, 20F))
-        assertThat(p2).isEqualTo(MutablePoint(3F, 40F))
-        assertThat(p3).isEqualTo(MutablePoint(1F, 40F))
+        assertThat(p0).isEqualTo(MutableVec(1F, 20F))
+        assertThat(p1).isEqualTo(MutableVec(3F, 20F))
+        assertThat(p2).isEqualTo(MutableVec(3F, 40F))
+        assertThat(p3).isEqualTo(MutableVec(1F, 40F))
     }
 
     @Test
     fun contains_returnsCorrectValuesWithPoint() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(10F, 600F), ImmutablePoint(40F, 900F))
-        val innerPoint = ImmutablePoint(30F, 700F)
-        val outerPoint = ImmutablePoint(70F, 2000F)
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(10F, 600F), ImmutableVec(40F, 900F))
+        val innerPoint = ImmutableVec(30F, 700F)
+        val outerPoint = ImmutableVec(70F, 2000F)
 
         assertThat(rect.contains(innerPoint)).isTrue()
         assertThat(rect.contains(outerPoint)).isFalse()
@@ -255,83 +211,10 @@
 
     @Test
     fun contains_returnsCorrectValuesWithBox() {
-        val outerRect =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(10F, 600F), ImmutablePoint(40F, 900F))
-        val innerRect =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(20F, 700F), ImmutablePoint(30F, 800F))
+        val outerRect = ImmutableBox.fromTwoPoints(ImmutableVec(10F, 600F), ImmutableVec(40F, 900F))
+        val innerRect = ImmutableBox.fromTwoPoints(ImmutableVec(20F, 700F), ImmutableVec(30F, 800F))
 
         assertThat(outerRect.contains(innerRect)).isTrue()
         assertThat(innerRect.contains(outerRect)).isFalse()
     }
-
-    @Test
-    fun copy_withNoArguments_returnsThis() {
-        val original = ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-
-        assertThat(original.copy()).isSameInstanceAs(original)
-    }
-
-    @Test
-    fun copy_withArguments_makesCopy() {
-        val x1 = 1F
-        val y1 = 2F
-        val x2 = 3F
-        val y2 = 4F
-        val original = ImmutableBox.fromTwoPoints(ImmutablePoint(x1, y1), ImmutablePoint(x2, y2))
-        // Different values that won't result in the min/max in either x or y dimension flipping.
-        val differentX1 = 0.5F
-        val differentY1 = 1.5F
-        val differentX2 = 2.5F
-        val differentY2 = 3.5F
-
-        // Change all values.
-        assertThat(original.copy(differentX1, differentY1, differentX2, differentY2))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(
-                    ImmutablePoint(differentX1, differentY1),
-                    ImmutablePoint(differentX2, differentY2),
-                )
-            )
-
-        // Change x1.
-        assertThat(original.copy(x1 = differentX1))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(differentX1, y1), ImmutablePoint(x2, y2))
-            )
-
-        // Change y1.
-        assertThat(original.copy(y1 = differentY1))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(x1, differentY1), ImmutablePoint(x2, y2))
-            )
-
-        // Change x2.
-        assertThat(original.copy(x2 = differentX2))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(x1, y1), ImmutablePoint(differentX2, y2))
-            )
-
-        // Change y2.
-        assertThat(original.copy(y2 = differentY2))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(x1, y1), ImmutablePoint(x2, differentY2))
-            )
-    }
-
-    @Test
-    fun copy_withArgumentsThatReverseBounds_makesCopyWith() {
-        val x1 = 1F
-        val y1 = 2F
-        val x2 = 3F
-        val y2 = 4F
-        val original = ImmutableBox.fromTwoPoints(ImmutablePoint(x1, y1), ImmutablePoint(x2, y2))
-        // Different value that results in the min/max in x dimension flipping.
-        val differentX1 = 5F
-
-        // Change x1 will flip x1 and x2 values.
-        assertThat(original.copy(x1 = differentX1))
-            .isEqualTo(
-                ImmutableBox.fromTwoPoints(ImmutablePoint(x2, y1), ImmutablePoint(differentX1, y2))
-            )
-    }
 }
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableParallelogramTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableParallelogramTest.kt
index c436f4c..c76c17f 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableParallelogramTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableParallelogramTest.kt
@@ -27,9 +27,9 @@
     @Test
     fun fromCenterAndDimensions_constructsCorrectImmutableParallelogram() {
         val parallelogram =
-            ImmutableParallelogram.fromCenterAndDimensions(ImmutablePoint(10f, 0f), 6f, 4f)
+            ImmutableParallelogram.fromCenterAndDimensions(ImmutableVec(10f, 0f), 6f, 4f)
 
-        assertThat(parallelogram.center).isEqualTo(ImmutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(ImmutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isZero()
@@ -40,13 +40,13 @@
     fun fromCenterDimensionsAndRotation_constructsCorrectImmutableParallelogram() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsAndRotation(
-                ImmutablePoint(10f, 0f),
+                ImmutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.FULL_TURN_RADIANS,
             )
 
-        assertThat(parallelogram.center).isEqualTo(ImmutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(ImmutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isZero()
@@ -57,14 +57,14 @@
     fun fromCenterDimensionsRotationAndShear_constructsCorrectImmutableParallelogram() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(10f, 0f),
+                ImmutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.HALF_TURN_RADIANS,
                 1f,
             )
 
-        assertThat(parallelogram.center).isEqualTo(ImmutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(ImmutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isWithin(1e-6f).of(Math.PI.toFloat())
@@ -75,7 +75,7 @@
     fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(10f, 10f),
+                ImmutableVec(10f, 10f),
                 12f,
                 2f,
                 Angle.HALF_TURN_RADIANS,
@@ -89,7 +89,7 @@
     fun equals_whenSameValues_returnsTrueAndSameHashCode() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -97,7 +97,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -113,13 +113,13 @@
         // An axis-aligned rectangle with center at (0,0) and width and height equal to 2
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(0f, 0f),
+                ImmutableVec(0f, 0f),
                 2f,
                 2f,
                 Angle.ZERO,
                 0f,
             )
-        val other = ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, -1f), ImmutablePoint(1f, 1f))
+        val other = ImmutableBox.fromTwoPoints(ImmutableVec(-1f, -1f), ImmutableVec(1f, 1f))
 
         assertThat(parallelogram).isNotEqualTo(other)
     }
@@ -128,7 +128,7 @@
     fun equals_whenDifferentCenter_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -136,7 +136,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(10f, -10.5f),
+                ImmutableVec(10f, -10.5f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -150,7 +150,7 @@
     fun equals_whenDifferentWidth_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 11f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -158,7 +158,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -172,7 +172,7 @@
     fun equals_whenDifferentHeight_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -180,7 +180,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -194,7 +194,7 @@
     fun equals_whenDifferentRotation_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -202,7 +202,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -216,7 +216,7 @@
     fun equals_whenDifferentShearFactor_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -224,7 +224,7 @@
             )
         val other =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(-10f, 10f),
+                ImmutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -238,14 +238,14 @@
     fun getters_returnCorrectValues() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                ImmutablePoint(3f, -5f),
+                ImmutableVec(3f, -5f),
                 8f,
                 -1f,
                 Angle.HALF_TURN_RADIANS,
                 0f,
             )
 
-        assertThat(parallelogram.center).isEqualTo(ImmutablePoint(3f, -5f))
+        assertThat(parallelogram.center).isEqualTo(ImmutableVec(3f, -5f))
         assertThat(parallelogram.width).isEqualTo(8f)
         assertThat(parallelogram.height).isEqualTo(-1f)
         assertThat(parallelogram.rotation).isEqualTo(Angle.HALF_TURN_RADIANS)
@@ -255,11 +255,11 @@
     @Test
     fun signedArea_returnsCorrectValue() {
         val parallelogram =
-            ImmutableParallelogram.fromCenterAndDimensions(ImmutablePoint(0f, 10f), 6f, 4f)
+            ImmutableParallelogram.fromCenterAndDimensions(ImmutableVec(0f, 10f), 6f, 4f)
         val degenerateParallelogram =
-            ImmutableParallelogram.fromCenterAndDimensions(ImmutablePoint(0f, 10f), 0f, 4f)
+            ImmutableParallelogram.fromCenterAndDimensions(ImmutableVec(0f, 10f), 0f, 4f)
         val negativeAreaParallelogram =
-            ImmutableParallelogram.fromCenterAndDimensions(ImmutablePoint(0f, 10f), 2f, -3f)
+            ImmutableParallelogram.fromCenterAndDimensions(ImmutableVec(0f, 10f), 2f, -3f)
 
         assertThat(parallelogram.signedArea()).isEqualTo(24f)
         assertThat(degenerateParallelogram.signedArea()).isZero()
@@ -270,7 +270,7 @@
     fun toString_returnsCorrectValue() {
         val parallelogramString =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(3f, -5f),
+                    ImmutableVec(3f, -5f),
                     8f,
                     -1f,
                     Angle.HALF_TURN_RADIANS,
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutablePointTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutablePointTest.kt
deleted file mode 100644
index 564f9bd..0000000
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutablePointTest.kt
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ImmutablePointTest {
-
-    @Test
-    fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
-        val point = ImmutablePoint(1f, 2f)
-
-        assertThat(point).isEqualTo(point)
-        assertThat(point.hashCode()).isEqualTo(point.hashCode())
-    }
-
-    @Test
-    fun equals_whenDifferentType_returnsFalse() {
-        val point = ImmutablePoint(1f, 2f)
-        val other = ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        assertThat(point).isNotEqualTo(other)
-    }
-
-    @Test
-    fun equals_whenSameValues_returnsTrueAndSameHashCode() {
-        val point = ImmutablePoint(-3f, 1.2f)
-        val other = ImmutablePoint(-3f, 1.2f)
-
-        assertThat(point).isEqualTo(other)
-        assertThat(point.hashCode()).isEqualTo(other.hashCode())
-    }
-
-    @Test
-    fun equals_whenFlippedValues_returnsFalse() {
-        val point = ImmutablePoint(10f, 2134f)
-        val other = ImmutablePoint(2134f, 10f)
-
-        assertThat(point).isNotEqualTo(other)
-    }
-
-    @Test
-    fun getters_returnCorrectValues() {
-        val point = ImmutablePoint(10f, 2134f)
-
-        assertThat(point.x).isEqualTo(10f)
-        assertThat(point.y).isEqualTo(2134f)
-    }
-
-    @Test
-    fun newMutable_returnsCorrectMutablePoint() {
-        val point = ImmutablePoint(2.1f, 2134f)
-
-        assertThat(point.newMutable()).isEqualTo(MutablePoint(2.1f, 2134f))
-    }
-
-    @Test
-    fun fillMutable_correctlyModifiesMutablePoint() {
-        val point = ImmutablePoint(2.1f, 2134f)
-        val output = MutablePoint()
-
-        point.fillMutable(output)
-
-        assertThat(output).isEqualTo(MutablePoint(2.1f, 2134f))
-    }
-
-    @Test
-    fun getVec_correctlyModifiesMutableVec() {
-        val point = ImmutablePoint(65.26f, -9228f)
-        val output = MutableVec()
-
-        point.getVec(output)
-
-        assertThat(output).isEqualTo(MutableVec(65.26f, -9228f))
-    }
-
-    @Test
-    fun copy_withNoArguments_returnsThis() {
-        val point = ImmutablePoint(1f, 2f)
-
-        assertThat(point.copy()).isSameInstanceAs(point)
-    }
-
-    @Test
-    fun copy_withArguments_makesCopy() {
-        val x = 1f
-        val y = 2f
-        val point = ImmutablePoint(x, y)
-        val differentX = 3f
-        val differentY = 4f
-
-        // Change both x and y.
-        assertThat(point.copy(x = differentX, y = differentY))
-            .isEqualTo(ImmutablePoint(differentX, differentY))
-
-        // Change x.
-        assertThat(point.copy(x = differentX)).isEqualTo(ImmutablePoint(differentX, y))
-
-        // Change y.
-        assertThat(point.copy(y = differentY)).isEqualTo(ImmutablePoint(x, differentY))
-    }
-
-    @Test
-    fun add_withPointThenVec_correctlyAddsAndFillsMutablePoint() {
-        val point = ImmutablePoint(10f, 40f)
-        val vec = ImmutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.add(point, vec, output)
-
-        assertThat(output).isEqualTo(MutablePoint(15f, 38f))
-    }
-
-    @Test
-    fun add_withVecThenPoint_correctlyAddsAndFillsMutablePoint() {
-        val point = ImmutablePoint(10f, 40f)
-        val vec = ImmutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.add(vec, point, output)
-
-        assertThat(output).isEqualTo(MutablePoint(15f, 38f))
-    }
-
-    @Test
-    fun subtract_pointMinusVec_correctlySubtractsAndFillsMutablePoint() {
-        val point = ImmutablePoint(10f, 40f)
-        val vec = ImmutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.subtract(point, vec, output)
-
-        assertThat(output).isEqualTo(MutablePoint(5f, 42f))
-    }
-
-    @Test
-    fun subtract_pointMinusPoint_correctlySubtractsAndFillsMutableVec() {
-        val lhsPoint = ImmutablePoint(10f, 40f)
-        val rhsPoint = ImmutablePoint(5f, -2f)
-        val output = MutableVec()
-
-        Point.subtract(lhsPoint, rhsPoint, output)
-
-        assertThat(output).isEqualTo(MutableVec(5f, 42f))
-    }
-}
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableVecTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableVecTest.kt
index e6cba99..ae332d8 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableVecTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ImmutableVecTest.kt
@@ -36,9 +36,9 @@
     @Test
     fun equals_whenDifferentType_returnsFalse() {
         val vec = ImmutableVec(1f, 2f)
-        val point = ImmutablePoint(1f, 2f)
+        val segment = ImmutableSegment(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f))
 
-        assertThat(vec).isNotEqualTo(point)
+        assertThat(vec).isNotEqualTo(segment)
     }
 
     @Test
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/IntersectionTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/IntersectionTest.kt
index dd0346a..87370c8 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/IntersectionTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/IntersectionTest.kt
@@ -159,7 +159,7 @@
         val shearFactor = 1f // = cotangent(PI/4), represents a 45-degree shear
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(center.x, center.y),
+                center = ImmutableVec(center.x, center.y),
                 width = width,
                 height = height,
                 rotation = Angle.ZERO,
@@ -210,7 +210,7 @@
     fun intersects_whenPointParallelogramDoesNotIntersect_returnsFalse() {
         val parallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(10f, 0f),
+                center = ImmutableVec(10f, 0f),
                 width = 1f,
                 height = 1f,
                 rotation = Angle.HALF_TURN_RADIANS / 4f,
@@ -236,8 +236,7 @@
 
     @Test
     fun intersects_whenPointBoxIntersects_returnsTrue() {
-        val rect =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(3.5f, 10.9f), ImmutablePoint(2.5f, 1.1f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(3.5f, 10.9f), ImmutableVec(2.5f, 1.1f))
         val vertex0 = ImmutableVec(3.5f, 10.9f)
         val vertex1 = MutableVec(3.5f, 1.1f)
         val vertex2 = ImmutableVec(2.5f, 10.9f)
@@ -270,7 +269,7 @@
 
     @Test
     fun intersects_whenPointBoxDoesNotIntersect_returnsFalse() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, 3.2f), ImmutablePoint(7f, 11.8f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(-1f, 3.2f), ImmutableVec(7f, 11.8f))
         val closeExteriorPoint = ImmutableVec(7.1f, 3.2f)
         val farExteriorPoint = ImmutableVec(-10f, -100f)
 
@@ -377,11 +376,11 @@
     fun intersects_whenSegmentBoxIntersects_returnsTrue() {
         val segment = ImmutableSegment(start = ImmutableVec(-1f, 3.2f), end = ImmutableVec(9f, 5f))
         val rectWithCommonMinPoint =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, 3.2f), ImmutablePoint(-10f, 0f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(-1f, 3.2f), ImmutableVec(-10f, 0f))
         val rectWithCommonMaxPoint =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(9f, 5f), ImmutablePoint(20f, 11.4f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(9f, 5f), ImmutableVec(20f, 11.4f))
         val intersectingBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(0f, 1f), ImmutablePoint(8f, 21f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(0f, 1f), ImmutableVec(8f, 21f))
 
         assertThat(segment.intersects(rectWithCommonMinPoint)).isTrue()
         assertThat(segment.intersects(rectWithCommonMaxPoint)).isTrue()
@@ -394,9 +393,8 @@
     @Test
     fun intersects_whenSegmentBoxDoesNotIntersect_returnsFalse() {
         val segment = ImmutableSegment(start = ImmutableVec(-1f, 3.2f), end = ImmutableVec(9f, 5f))
-        val closeBox = ImmutableBox.fromTwoPoints(ImmutablePoint(9.1f, 5f), ImmutablePoint(10f, 6f))
-        val farBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(-10f, -2f), ImmutablePoint(-21f, -8f))
+        val closeBox = ImmutableBox.fromTwoPoints(ImmutableVec(9.1f, 5f), ImmutableVec(10f, 6f))
+        val farBox = ImmutableBox.fromTwoPoints(ImmutableVec(-10f, -2f), ImmutableVec(-21f, -8f))
 
         assertThat(segment.intersects(closeBox)).isFalse()
         assertThat(segment.intersects(farBox)).isFalse()
@@ -409,7 +407,7 @@
         val segment = ImmutableSegment(start = ImmutableVec(-1f, 3.2f), end = ImmutableVec(9f, 5f))
         val parallelogramWithCommonVertex =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(1f, 6.2f),
+                center = ImmutableVec(1f, 6.2f),
                 width = 4f,
                 height = 6f,
                 rotation = Angle.ZERO,
@@ -417,7 +415,7 @@
             )
         val intersectingParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(4f, 4.1f),
+                center = ImmutableVec(4f, 4.1f),
                 width = 4f,
                 height = 6f,
                 rotation = Angle.ZERO,
@@ -435,7 +433,7 @@
         val segment = ImmutableSegment(start = ImmutableVec(-1f, 3.2f), end = ImmutableVec(9f, 5f))
         val closeParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(10.1f, 7f),
+                center = ImmutableVec(10.1f, 7f),
                 width = 2f,
                 height = 4f,
                 rotation = Angle.ZERO,
@@ -443,7 +441,7 @@
             )
         val farParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(-100f, -103.1f),
+                center = ImmutableVec(-100f, -103.1f),
                 width = 4f,
                 height = 7.2f,
                 rotation = Angle.QUARTER_TURN_RADIANS,
@@ -547,11 +545,11 @@
                 p2 = ImmutableVec(4.2f, 10f),
             )
         val rectWithCommonP2 =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(4.2f, 10f), ImmutablePoint(7.9f, 19.2f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(4.2f, 10f), ImmutableVec(7.9f, 19.2f))
         val rectWithCommonEdge =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(-10f, 1f), ImmutablePoint(0f, 31.6f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(-10f, 1f), ImmutableVec(0f, 31.6f))
         val intersectingBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 20f), ImmutablePoint(6.5f, 31.9f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 20f), ImmutableVec(6.5f, 31.9f))
 
         assertThat(triangle.intersects(rectWithCommonP2)).isTrue()
         assertThat(triangle.intersects(rectWithCommonEdge)).isTrue()
@@ -569,10 +567,8 @@
                 p1 = ImmutableVec(0f, 31.6f),
                 p2 = ImmutableVec(4.2f, 10f),
             )
-        val closeBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(0f, 0.9f), ImmutablePoint(-51.1f, -2f))
-        val farBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(100f, 200f), ImmutablePoint(300f, 400f))
+        val closeBox = ImmutableBox.fromTwoPoints(ImmutableVec(0f, 0.9f), ImmutableVec(-51.1f, -2f))
+        val farBox = ImmutableBox.fromTwoPoints(ImmutableVec(100f, 200f), ImmutableVec(300f, 400f))
 
         assertThat(triangle.intersects(closeBox)).isFalse()
         assertThat(triangle.intersects(farBox)).isFalse()
@@ -590,7 +586,7 @@
             )
         val parallelogramWithCommonP1 =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(1.5f, 32.6f),
+                center = ImmutableVec(1.5f, 32.6f),
                 width = 3f,
                 height = 2f,
                 rotation = Angle.ZERO,
@@ -598,7 +594,7 @@
             )
         val parallelogramWithCommonEdge =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(-1f, 16.3f),
+                center = ImmutableVec(-1f, 16.3f),
                 width = 2f,
                 height = 15.3f,
                 rotation = Angle.ZERO,
@@ -606,7 +602,7 @@
             )
         val intersectingParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(2.1f, 17.4f),
+                center = ImmutableVec(2.1f, 17.4f),
                 width = 10f,
                 height = 19.4f,
                 rotation = Angle.ZERO,
@@ -631,7 +627,7 @@
             )
         val closeParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(-5.1f, 2f),
+                center = ImmutableVec(-5.1f, 2f),
                 width = 10f,
                 height = 13.2f,
                 rotation = Angle.ZERO,
@@ -639,7 +635,7 @@
             )
         val farParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(100f, 200f),
+                center = ImmutableVec(100f, 200f),
                 width = 0.6f,
                 height = 2.3f,
                 rotation = Angle.QUARTER_TURN_RADIANS,
@@ -654,8 +650,8 @@
 
     @Test
     fun intersects_forEqualBoxs_returnsTrue() {
-        val rect1 = ImmutableBox.fromTwoPoints(ImmutablePoint(0f, 1f), ImmutablePoint(31.6f, 10f))
-        val rect2 = ImmutableBox.fromTwoPoints(ImmutablePoint(0f, 1f), ImmutablePoint(31.6f, 10f))
+        val rect1 = ImmutableBox.fromTwoPoints(ImmutableVec(0f, 1f), ImmutableVec(31.6f, 10f))
+        val rect2 = ImmutableBox.fromTwoPoints(ImmutableVec(0f, 1f), ImmutableVec(31.6f, 10f))
 
         assertThat(rect1.intersects(rect1)).isTrue()
         assertThat(rect1.intersects(rect2)).isTrue()
@@ -664,13 +660,13 @@
 
     @Test
     fun intersects_whenBoxBoxIntersects_returnsTrue() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 1f), ImmutablePoint(31.6f, 10f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 1f), ImmutableVec(31.6f, 10f))
         val rectWithCommonVertex =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 1f), ImmutablePoint(-3f, -6.5f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 1f), ImmutableVec(-3f, -6.5f))
         val rectWithCommonEdge =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(31.6f, 5f), ImmutablePoint(67.9f, 2f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(31.6f, 5f), ImmutableVec(67.9f, 2f))
         val intersectingBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(6.7f, 3f), ImmutablePoint(20f, 100.2f))
+            ImmutableBox.fromTwoPoints(ImmutableVec(6.7f, 3f), ImmutableVec(20f, 100.2f))
 
         assertThat(rect.intersects(rectWithCommonVertex)).isTrue()
         assertThat(rect.intersects(rectWithCommonEdge)).isTrue()
@@ -682,11 +678,9 @@
 
     @Test
     fun intersects_whenBoxBoxDoesNotIntersect_returnsFalse() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 1f), ImmutablePoint(31.6f, 10f))
-        val closeBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(2f, 1f), ImmutablePoint(-10f, -11f))
-        val farBox =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(100f, 200f), ImmutablePoint(300f, 400f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 1f), ImmutableVec(31.6f, 10f))
+        val closeBox = ImmutableBox.fromTwoPoints(ImmutableVec(2f, 1f), ImmutableVec(-10f, -11f))
+        val farBox = ImmutableBox.fromTwoPoints(ImmutableVec(100f, 200f), ImmutableVec(300f, 400f))
 
         assertThat(rect.intersects(closeBox)).isFalse()
         assertThat(rect.intersects(farBox)).isFalse()
@@ -696,10 +690,10 @@
 
     @Test
     fun intersects_whenBoxParallelogramIntersects_returnsTrue() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 1f), ImmutablePoint(31.6f, 10f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 1f), ImmutableVec(31.6f, 10f))
         val parallelogramWithCommonVertex =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(26.6f, 8f),
+                center = ImmutableVec(26.6f, 8f),
                 width = 10f,
                 height = 4f,
                 rotation = Angle.ZERO,
@@ -707,7 +701,7 @@
             )
         val parallelogramWithCommonEdge =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(10f, 0f),
+                center = ImmutableVec(10f, 0f),
                 width = 10f,
                 height = 2f,
                 rotation = Angle.ZERO,
@@ -715,7 +709,7 @@
             )
         val intersectingParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(10f, 5f),
+                center = ImmutableVec(10f, 5f),
                 width = 6f,
                 height = 4f,
                 rotation = Angle.ZERO,
@@ -732,10 +726,10 @@
 
     @Test
     fun intersects_whenBoxParallelogramDoesNotIntersect_returnsFalse() {
-        val rect = ImmutableBox.fromTwoPoints(ImmutablePoint(2.1f, 1f), ImmutablePoint(31.6f, 10f))
+        val rect = ImmutableBox.fromTwoPoints(ImmutableVec(2.1f, 1f), ImmutableVec(31.6f, 10f))
         val closeParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(0f, 1f),
+                center = ImmutableVec(0f, 1f),
                 width = 4f,
                 height = 10f,
                 rotation = Angle.ZERO,
@@ -743,7 +737,7 @@
             )
         val farParallelogram =
             ImmutableParallelogram.fromCenterDimensionsRotationAndShear(
-                center = ImmutablePoint(100f, 200f),
+                center = ImmutableVec(100f, 200f),
                 width = 0.6f,
                 height = 2.3f,
                 rotation = Angle.QUARTER_TURN_RADIANS,
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshAttributeUnpackingParamsTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshAttributeUnpackingParamsTest.kt
index c2011d9..590e4e3 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshAttributeUnpackingParamsTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshAttributeUnpackingParamsTest.kt
@@ -138,8 +138,7 @@
                     )
                 ),
             )
-        val notATransform =
-            ImmutableBox.fromTwoPoints(ImmutablePoint(2F, 4F), ImmutablePoint(1F, 3F))
+        val notATransform = ImmutableBox.fromTwoPoints(ImmutableVec(2F, 4F), ImmutableVec(1F, 3F))
 
         for (transform in transforms) {
             assertThat(transform).isNotEqualTo(notATransform)
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshTest.kt
index 5803e2b..6107970 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MeshTest.kt
@@ -95,9 +95,9 @@
     fun fillPosition_shouldThrow() {
         val mesh = Mesh()
 
-        assertFailsWith { mesh.fillPosition(-1, MutablePoint()) }
-        assertFailsWith { mesh.fillPosition(0, MutablePoint()) }
-        assertFailsWith { mesh.fillPosition(1, MutablePoint()) }
+        assertFailsWith { mesh.fillPosition(-1, MutableVec()) }
+        assertFailsWith { mesh.fillPosition(0, MutableVec()) }
+        assertFailsWith { mesh.fillPosition(1, MutableVec()) }
     }
 
     @Test
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ModeledShapeTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ModeledShapeTest.kt
deleted file mode 100644
index 7b2ede5..0000000
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ModeledShapeTest.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import com.google.common.truth.Truth.assertThat
-import kotlin.test.assertFailsWith
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ModeledShapeTest {
-
-    @Test
-    fun bounds_shouldBeEmpty() {
-        val modeledShape = ModeledShape()
-
-        assertThat(modeledShape.bounds).isNull()
-    }
-
-    @Test
-    fun renderGroupCount_whenEmptyShape_shouldBeZero() {
-        val modeledShape = ModeledShape()
-
-        assertThat(modeledShape.renderGroupCount).isEqualTo(0)
-    }
-
-    @Test
-    fun outlineCount_whenEmptyShape_shouldThrow() {
-        val modeledShape = ModeledShape()
-
-        assertFailsWith { modeledShape.outlineCount(-1) }
-        assertFailsWith { modeledShape.outlineCount(0) }
-        assertFailsWith { modeledShape.outlineCount(1) }
-    }
-
-    @Test
-    fun outlineVertexCount_whenEmptyShape_shouldThrow() {
-        val modeledShape = ModeledShape()
-
-        assertFailsWith { modeledShape.outlineVertexCount(-1, 0) }
-        assertFailsWith { modeledShape.outlineVertexCount(0, 0) }
-        assertFailsWith { modeledShape.outlineVertexCount(1, 0) }
-    }
-
-    @Test
-    fun fillOutlinePosition_whenEmptyShape_shouldThrow() {
-        val modeledShape = ModeledShape()
-
-        assertFailsWith {
-            modeledShape.fillOutlinePosition(-1, 0, 0, MutablePoint())
-        }
-        assertFailsWith {
-            modeledShape.fillOutlinePosition(0, 0, 0, MutablePoint())
-        }
-        assertFailsWith {
-            modeledShape.fillOutlinePosition(1, 0, 0, MutablePoint())
-        }
-    }
-
-    @Test
-    fun toString_returnsAString() {
-        val string = ModeledShape().toString()
-
-        // Not elaborate checks - this test mainly exists to ensure that toString doesn't crash.
-        assertThat(string).contains("ModeledShape")
-        assertThat(string).contains("bounds")
-        assertThat(string).contains("meshes")
-        assertThat(string).contains("nativeAddress")
-    }
-}
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableBoxTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableBoxTest.kt
index 94b695f..4b6d1b6 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableBoxTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableBoxTest.kt
@@ -35,8 +35,8 @@
     }
 
     @Test
-    fun fillFromCenterAndDimensions_correctlyModifiesMutableBox() {
-        val rect = MutableBox().fillFromCenterAndDimensions(ImmutablePoint(20f, -50f), 10f, 20f)
+    fun populateFromCenterAndDimensions_correctlyModifiesMutableBox() {
+        val rect = MutableBox().populateFromCenterAndDimensions(ImmutableVec(20f, -50f), 10f, 20f)
 
         assertThat(rect.xMin).isEqualTo(15f)
         assertThat(rect.xMax).isEqualTo(25f)
@@ -47,9 +47,9 @@
     }
 
     @Test
-    fun fillFromTwoPoints_correctlyModifiesMutableBox() {
+    fun populateFromTwoPoints_correctlyModifiesMutableBox() {
         val rect =
-            MutableBox().fillFromTwoPoints(MutablePoint(20f, -50f), ImmutablePoint(-70f, 100f))
+            MutableBox().populateFromTwoPoints(MutableVec(20f, -50f), ImmutableVec(-70f, 100f))
 
         assertThat(rect.xMin).isEqualTo(-70f)
         assertThat(rect.xMax).isEqualTo(20f)
@@ -61,7 +61,7 @@
 
     @Test
     fun minMaxFields_whenAllZeroes_allAreZero() {
-        val zeroes = MutableBox().fillFromTwoPoints(ImmutablePoint(0F, 0F), ImmutablePoint(0F, 0F))
+        val zeroes = MutableBox().populateFromTwoPoints(ImmutableVec(0F, 0F), ImmutableVec(0F, 0F))
         assertThat(zeroes.xMin).isEqualTo(0F)
         assertThat(zeroes.yMin).isEqualTo(0F)
         assertThat(zeroes.xMax).isEqualTo(0F)
@@ -71,7 +71,7 @@
     @Test
     fun minMaxFields_whenDeclaredInMinMaxOrder_matchOrder() {
         val inOrder =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(-1F, -2F), ImmutablePoint(3F, 4F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(-1F, -2F), ImmutableVec(3F, 4F))
         assertThat(inOrder.xMin).isEqualTo(-1F)
         assertThat(inOrder.yMin).isEqualTo(-2F)
         assertThat(inOrder.xMax).isEqualTo(3F)
@@ -81,7 +81,7 @@
     @Test
     fun minMaxFields_whenDeclaredOutOfOrder_doNotMatchOrder() {
         val outOfOrder =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(-3F, -4F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(-3F, -4F))
         assertThat(outOfOrder.xMin).isEqualTo(-3F)
         assertThat(outOfOrder.yMin).isEqualTo(-4F)
         assertThat(outOfOrder.xMax).isEqualTo(1F)
@@ -90,7 +90,7 @@
 
     @Test
     fun widthHeight_whenAllZeroes_areAllZero() {
-        val zeroes = MutableBox().fillFromTwoPoints(ImmutablePoint(0F, 0F), ImmutablePoint(0F, 0F))
+        val zeroes = MutableBox().populateFromTwoPoints(ImmutableVec(0F, 0F), ImmutableVec(0F, 0F))
 
         assertThat(zeroes.width).isEqualTo(0)
         assertThat(zeroes.height).isEqualTo(0)
@@ -99,7 +99,7 @@
     @Test
     fun widthHeight_whenDeclaredInOrder_areCorrectValues() {
         val inOrder =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(-1F, -2F), ImmutablePoint(3F, 4F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(-1F, -2F), ImmutableVec(3F, 4F))
 
         assertThat(inOrder.width).isEqualTo(4F)
         assertThat(inOrder.height).isEqualTo(6F)
@@ -108,7 +108,7 @@
     @Test
     fun widthHeight_whenDeclaredOutOfOrder_areCorrectValues() {
         val outOfOrder =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(-3F, -4F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(-3F, -4F))
 
         assertThat(outOfOrder.width).isEqualTo(4F)
         assertThat(outOfOrder.height).isEqualTo(6F)
@@ -116,9 +116,9 @@
 
     @Test
     fun widthHeight_whenValuesChanged_areCorrectValues() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(-3F, -4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(-3F, -4F))
 
-        rect.fillFromTwoPoints(MutablePoint(-20f, -5f), ImmutablePoint(30f, 7f))
+        rect.populateFromTwoPoints(MutableVec(-20f, -5f), ImmutableVec(30f, 7f))
 
         assertThat(rect.width).isEqualTo(50F)
         assertThat(rect.height).isEqualTo(12F)
@@ -126,66 +126,66 @@
 
     @Test
     fun setXBounds_whenInOrder_changesXMinAndXMax() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         rect.setXBounds(5F, 7F)
 
         assertThat(rect)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(5F, 2F), ImmutablePoint(7F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(5F, 2F), ImmutableVec(7F, 4F))
             )
     }
 
     @Test
     fun setXBounds_whenNotInOrder_changesXMinAndXMax() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         rect.setXBounds(7F, 5F)
 
         assertThat(rect)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(5F, 2F), ImmutablePoint(7F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(5F, 2F), ImmutableVec(7F, 4F))
             )
     }
 
     @Test
     fun setYBounds_whenInOrder_changesXMinAndXMax() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         rect.setYBounds(6F, 8F)
 
         assertThat(rect)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 6F), ImmutablePoint(3F, 8F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, 6F), ImmutableVec(3F, 8F))
             )
     }
 
     @Test
     fun setYBounds_whenNotInOrder_changesXMinAndXMax() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         rect.setYBounds(8F, 6F)
 
         assertThat(rect)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 6F), ImmutablePoint(3F, 8F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, 6F), ImmutableVec(3F, 8F))
             )
     }
 
     @Test
     fun populateFrom_correctlyPopulatesFromBox() {
-        val source = ImmutableBox.fromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val source = ImmutableBox.fromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
         val dest = MutableBox().populateFrom(source)
 
         assertThat(dest)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
             )
     }
 
     @Test
     fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect).isEqualTo(rect)
         assertThat(rect.hashCode()).isEqualTo(rect.hashCode())
@@ -193,15 +193,15 @@
 
     @Test
     fun equals_whenDifferentType_returnsFalse() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
-        assertThat(rect).isNotEqualTo(ImmutablePoint(1F, 2F))
+        assertThat(rect).isNotEqualTo(ImmutableVec(1F, 2F))
     }
 
     @Test
     fun equals_whenSameValues_returnsTrueAndSameHashCode() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        val other = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
+        val other = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect).isEqualTo(other)
         assertThat(rect.hashCode()).isEqualTo(other.hashCode())
@@ -209,8 +209,8 @@
 
     @Test
     fun equals_whenSameValuesOutOfOrder_returnsTrueAndSameHashCode() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-        val other = MutableBox().fillFromTwoPoints(ImmutablePoint(3F, 4F), ImmutablePoint(1F, 2F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
+        val other = MutableBox().populateFromTwoPoints(ImmutableVec(3F, 4F), ImmutableVec(1F, 2F))
 
         assertThat(rect).isEqualTo(other)
         assertThat(rect.hashCode()).isEqualTo(other.hashCode())
@@ -218,63 +218,49 @@
 
     @Test
     fun equals_whenDifferentXMin_returnsFalse() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect)
             .isNotEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-1F, 2F), ImmutablePoint(3F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-1F, 2F), ImmutableVec(3F, 4F))
             )
     }
 
     @Test
     fun equals_whenDifferentYMin_returnsFalse() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect)
             .isNotEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, -2F), ImmutablePoint(3F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, -2F), ImmutableVec(3F, 4F))
             )
     }
 
     @Test
     fun equals_whenDifferentXMax_returnsFalse() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect)
             .isNotEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(30F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(30F, 4F))
             )
     }
 
     @Test
     fun equals_whenDifferentYMax_returnsFalse() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
         assertThat(rect)
             .isNotEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 40F))
-            )
-    }
-
-    @Test
-    fun copy_returnsEqualValueThatCannotModifyOriginal() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
-
-        val copy = rect.copy()
-        assertThat(copy).isEqualTo(rect)
-
-        copy.fillFromTwoPoints(ImmutablePoint(5F, 6F), ImmutablePoint(7F, 8F))
-        assertThat(rect)
-            .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 40F))
             )
     }
 
     @Test
     fun overwriteFromValues_whenInOrder_changesAllValues() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
-        rect.fillFromTwoPoints(ImmutablePoint(5F, 6F), ImmutablePoint(7F, 8F))
+        rect.populateFromTwoPoints(ImmutableVec(5F, 6F), ImmutableVec(7F, 8F))
 
         assertThat(rect.xMin).isEqualTo(5F)
         assertThat(rect.yMin).isEqualTo(6F)
@@ -284,9 +270,9 @@
 
     @Test
     fun overwriteFromValues_whenOutOfOrder_changesAllValues() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 2F), ImmutablePoint(3F, 4F))
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 2F), ImmutableVec(3F, 4F))
 
-        rect.fillFromTwoPoints(ImmutablePoint(-1F, -2F), ImmutablePoint(-3F, -4F))
+        rect.populateFromTwoPoints(ImmutableVec(-1F, -2F), ImmutableVec(-3F, -4F))
 
         assertThat(rect.xMin).isEqualTo(-3F)
         assertThat(rect.yMin).isEqualTo(-4F)
@@ -295,35 +281,35 @@
     }
 
     @Test
-    fun center_modifiesMutablePoint() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 20F), ImmutablePoint(3F, 40F))
-        val outCenter = MutablePoint()
-        rect.center(outCenter)
+    fun populateCenter_modifiesMutableVec() {
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 20F), ImmutableVec(3F, 40F))
+        val outCenter = MutableVec()
+        rect.populateCenter(outCenter)
 
-        assertThat(outCenter).isEqualTo(MutablePoint(2F, 30F))
+        assertThat(outCenter).isEqualTo(MutableVec(2F, 30F))
     }
 
     @Test
     fun corners_modifiesMutablePoints() {
-        val rect = MutableBox().fillFromTwoPoints(ImmutablePoint(1F, 20F), ImmutablePoint(3F, 40F))
-        val p0 = MutablePoint()
-        val p1 = MutablePoint()
-        val p2 = MutablePoint()
-        val p3 = MutablePoint()
+        val rect = MutableBox().populateFromTwoPoints(ImmutableVec(1F, 20F), ImmutableVec(3F, 40F))
+        val p0 = MutableVec()
+        val p1 = MutableVec()
+        val p2 = MutableVec()
+        val p3 = MutableVec()
         rect.corners(p0, p1, p2, p3)
 
-        assertThat(p0).isEqualTo(MutablePoint(1F, 20F))
-        assertThat(p1).isEqualTo(MutablePoint(3F, 20F))
-        assertThat(p2).isEqualTo(MutablePoint(3F, 40F))
-        assertThat(p3).isEqualTo(MutablePoint(1F, 40F))
+        assertThat(p0).isEqualTo(MutableVec(1F, 20F))
+        assertThat(p1).isEqualTo(MutableVec(3F, 20F))
+        assertThat(p2).isEqualTo(MutableVec(3F, 40F))
+        assertThat(p3).isEqualTo(MutableVec(1F, 40F))
     }
 
     @Test
-    fun contains_returnsCorrectValuesWithPoint() {
+    fun contains_returnsCorrectValuesWithVec() {
         val rect =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(10F, 600F), ImmutablePoint(40F, 900F))
-        val innerPoint = ImmutablePoint(30F, 700F)
-        val outerPoint = ImmutablePoint(70F, 2000F)
+            MutableBox().populateFromTwoPoints(ImmutableVec(10F, 600F), ImmutableVec(40F, 900F))
+        val innerPoint = ImmutableVec(30F, 700F)
+        val outerPoint = ImmutableVec(70F, 2000F)
 
         assertThat(rect.contains(innerPoint)).isTrue()
         assertThat(rect.contains(outerPoint)).isFalse()
@@ -332,9 +318,9 @@
     @Test
     fun contains_returnsCorrectValuesWithBox() {
         val outerRect =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(10F, 600F), ImmutablePoint(40F, 900F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(10F, 600F), ImmutableVec(40F, 900F))
         val innerRect =
-            MutableBox().fillFromTwoPoints(ImmutablePoint(20F, 700F), ImmutablePoint(30F, 800F))
+            MutableBox().populateFromTwoPoints(ImmutableVec(20F, 700F), ImmutableVec(30F, 800F))
 
         assertThat(outerRect.contains(innerRect)).isTrue()
         assertThat(innerRect.contains(outerRect)).isFalse()
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableParallelogramTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableParallelogramTest.kt
index 9d737bd..db93597 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableParallelogramTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableParallelogramTest.kt
@@ -28,7 +28,7 @@
     fun defaultConstructor_constructsCorrectMutableParallelogram() {
         val parallelogram = MutableParallelogram()
 
-        assertThat(parallelogram.center).isEqualTo(MutablePoint(0f, 0f))
+        assertThat(parallelogram.center).isEqualTo(MutableVec(0f, 0f))
         assertThat(parallelogram.width).isZero()
         assertThat(parallelogram.height).isZero()
         assertThat(parallelogram.rotation).isZero()
@@ -38,7 +38,7 @@
     @Test
     fun setCenter_changesCenter() {
         val parallelogram = MutableParallelogram()
-        val newCenter = MutablePoint(5f, -2f)
+        val newCenter = MutableVec(5f, -2f)
         parallelogram.center = newCenter
         assertThat(parallelogram.center).isEqualTo(newCenter)
     }
@@ -47,7 +47,7 @@
     fun setWidth_toNegativeValue_forcesNormalizationOfParallelogram() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsAndRotation(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -65,7 +65,7 @@
     fun setRotation_toOutOfRangeNormalRange_forcesNormalizationOfAngle() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsAndRotation(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -77,9 +77,9 @@
     @Test
     fun fromCenterAndDimensions_constructsCorrectMutableParallelogram() {
         val parallelogram =
-            MutableParallelogram.fromCenterAndDimensions(MutablePoint(10f, 0f), 6f, 4f)
+            MutableParallelogram.fromCenterAndDimensions(MutableVec(10f, 0f), 6f, 4f)
 
-        assertThat(parallelogram.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isZero()
@@ -89,9 +89,9 @@
     @Test
     fun fromCenterAndDimensions_forNegativeWidth_constructsCorrectMutableParallelogram() {
         val parallelogramWithNegativeWidth =
-            MutableParallelogram.fromCenterAndDimensions(MutablePoint(10f, 0f), -6f, 4f)
+            MutableParallelogram.fromCenterAndDimensions(MutableVec(10f, 0f), -6f, 4f)
 
-        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogramWithNegativeWidth.width).isEqualTo(6f)
         assertThat(parallelogramWithNegativeWidth.height).isEqualTo(-4f)
         assertThat(parallelogramWithNegativeWidth.rotation).isEqualTo(Math.PI.toFloat())
@@ -102,13 +102,13 @@
     fun fromCenterDimensionsAndRotation_constructsCorrectMutableParallelogram() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsAndRotation(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.FULL_TURN_RADIANS,
             )
 
-        assertThat(parallelogram.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isZero()
@@ -119,13 +119,13 @@
     fun fromCenterDimensionsAndRotation_forNegativeWidth_constructsCorrectMutableParallelogram() {
         val parallelogramWithNegativeWidth =
             MutableParallelogram.fromCenterDimensionsAndRotation(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 -6f,
                 4f,
                 Angle.FULL_TURN_RADIANS,
             )
 
-        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogramWithNegativeWidth.width).isEqualTo(6f)
         assertThat(parallelogramWithNegativeWidth.height).isEqualTo(-4f)
         assertThat(parallelogramWithNegativeWidth.rotation).isWithin(1e-6f).of(Math.PI.toFloat())
@@ -136,14 +136,14 @@
     fun fromCenterDimensionsRotationAndShear_constructsCorrectMutableParallelogram() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 6f,
                 4f,
                 Angle.HALF_TURN_RADIANS,
                 1f,
             )
 
-        assertThat(parallelogram.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogram.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogram.width).isEqualTo(6f)
         assertThat(parallelogram.height).isEqualTo(4f)
         assertThat(parallelogram.rotation).isWithin(1e-6f).of(Math.PI.toFloat())
@@ -154,14 +154,14 @@
     fun fromCenterDimensionsRotationAndShear_forNegativeWidth_constructsCorrectMutableParallelogram() {
         val parallelogramWithNegativeWidth =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(10f, 0f),
+                MutableVec(10f, 0f),
                 -6f,
                 4f,
                 Angle.FULL_TURN_RADIANS,
                 1f,
             )
 
-        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutablePoint(10f, 0f))
+        assertThat(parallelogramWithNegativeWidth.center).isEqualTo(MutableVec(10f, 0f))
         assertThat(parallelogramWithNegativeWidth.width).isEqualTo(6f)
         assertThat(parallelogramWithNegativeWidth.height).isEqualTo(-4f)
         assertThat(parallelogramWithNegativeWidth.rotation).isWithin(1e-6f).of(Math.PI.toFloat())
@@ -172,7 +172,7 @@
     fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(10f, 10f),
+                MutableVec(10f, 10f),
                 12f,
                 2f,
                 Angle.HALF_TURN_RADIANS,
@@ -186,7 +186,7 @@
     fun equals_whenSameValues_returnsTrueAndSameHashCode() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -194,7 +194,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -210,13 +210,13 @@
         // An axis-aligned rectangle with center at (0,0) and width and height equal to 2
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(0f, 0f),
+                MutableVec(0f, 0f),
                 2f,
                 2f,
                 Angle.ZERO,
                 0f,
             )
-        val other = MutableBox().fillFromTwoPoints(ImmutablePoint(-1f, -1f), ImmutablePoint(1f, 1f))
+        val other = MutableBox().populateFromTwoPoints(ImmutableVec(-1f, -1f), ImmutableVec(1f, 1f))
 
         assertThat(parallelogram).isNotEqualTo(other)
     }
@@ -225,7 +225,7 @@
     fun equals_whenDifferentCenter_returnsFalse() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -233,7 +233,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(10f, -10.5f),
+                MutableVec(10f, -10.5f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -247,7 +247,7 @@
     fun equals_whenDifferentWidth_returnsFalse() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 11f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -255,7 +255,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -269,7 +269,7 @@
     fun equals_whenDifferentHeight_returnsFalse() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -277,7 +277,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -291,7 +291,7 @@
     fun equals_whenDifferentRotation_returnsFalse() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -299,7 +299,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.QUARTER_TURN_RADIANS,
@@ -313,7 +313,7 @@
     fun equals_whenDifferentShearFactor_returnsFalse() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -321,7 +321,7 @@
             )
         val other =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(-10f, 10f),
+                MutableVec(-10f, 10f),
                 12f,
                 -7.5f,
                 Angle.HALF_TURN_RADIANS,
@@ -335,14 +335,14 @@
     fun getters_returnCorrectValues() {
         val parallelogram =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                MutablePoint(3f, -5f),
+                MutableVec(3f, -5f),
                 8f,
                 -1f,
                 Angle.HALF_TURN_RADIANS,
                 0f,
             )
 
-        assertThat(parallelogram.center).isEqualTo(MutablePoint(3f, -5f))
+        assertThat(parallelogram.center).isEqualTo(MutableVec(3f, -5f))
         assertThat(parallelogram.width).isEqualTo(8f)
         assertThat(parallelogram.height).isEqualTo(-1f)
         assertThat(parallelogram.rotation).isEqualTo(Angle.HALF_TURN_RADIANS)
@@ -352,11 +352,11 @@
     @Test
     fun signedArea_returnsCorrectValue() {
         val parallelogram =
-            MutableParallelogram.fromCenterAndDimensions(MutablePoint(0f, 10f), 6f, 4f)
+            MutableParallelogram.fromCenterAndDimensions(MutableVec(0f, 10f), 6f, 4f)
         val degenerateParallelogram =
-            MutableParallelogram.fromCenterAndDimensions(MutablePoint(0f, 10f), 0f, 4f)
+            MutableParallelogram.fromCenterAndDimensions(MutableVec(0f, 10f), 0f, 4f)
         val negativeAreaParallelogram =
-            MutableParallelogram.fromCenterAndDimensions(MutablePoint(0f, 10f), 2f, -3f)
+            MutableParallelogram.fromCenterAndDimensions(MutableVec(0f, 10f), 2f, -3f)
 
         assertThat(parallelogram.signedArea()).isEqualTo(24f)
         assertThat(degenerateParallelogram.signedArea()).isZero()
@@ -367,7 +367,7 @@
     fun toString_returnsCorrectValue() {
         val parallelogramString =
             MutableParallelogram.fromCenterDimensionsRotationAndShear(
-                    ImmutablePoint(3f, -5f),
+                    ImmutableVec(3f, -5f),
                     8f,
                     -1f,
                     Angle.HALF_TURN_RADIANS,
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutablePointTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutablePointTest.kt
deleted file mode 100644
index 2279b4b..0000000
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutablePointTest.kt
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class MutablePointTest {
-
-    @Test
-    fun equals_whenSameInstance_returnsTrueAndSameHashCode() {
-        val point = MutablePoint(1f, 2f)
-
-        assertThat(point).isEqualTo(point)
-        assertThat(point.hashCode()).isEqualTo(point.hashCode())
-    }
-
-    @Test
-    fun equals_whenDifferentType_returnsFalse() {
-        val point = MutablePoint(1f, 2f)
-        val vec = ImmutableVec(1f, 2f)
-
-        assertThat(point).isNotEqualTo(vec)
-    }
-
-    @Test
-    fun equals_whenSameInterface_returnsTrue() {
-        val point = MutablePoint(1f, 2f)
-        val other = ImmutablePoint(1f, 2f)
-
-        assertThat(point).isEqualTo(other)
-    }
-
-    @Test
-    fun equals_whenSameValues_returnsTrueAndSameHashCode() {
-        val point = MutablePoint(-3f, 1.2f)
-        val other = MutablePoint(-3f, 1.2f)
-
-        assertThat(point).isEqualTo(other)
-        assertThat(point.hashCode()).isEqualTo(other.hashCode())
-    }
-
-    @Test
-    fun equals_whenFlippedValues_returnsFalse() {
-        val point = MutablePoint(10f, 2134f)
-        val other = MutablePoint(2134f, 10f)
-
-        assertThat(point).isNotEqualTo(other)
-    }
-
-    @Test
-    fun getters_returnCorrectValues() {
-        val point = MutablePoint(10f, 2134f)
-
-        assertThat(point.x).isEqualTo(10f)
-        assertThat(point.y).isEqualTo(2134f)
-    }
-
-    @Test
-    fun setters_gettersReturnNewValues() {
-        val point = MutablePoint(99f, 1234f)
-
-        point.x = 10f
-        point.y = 2134f
-
-        assertThat(point.x).isEqualTo(10f)
-        assertThat(point.y).isEqualTo(2134f)
-    }
-
-    @Test
-    fun build_returnsPointWithSameValues() {
-        val point = MutablePoint(10f, 2134f)
-
-        val builtPoint = point.build()
-        assertThat(builtPoint).isEqualTo(ImmutablePoint(10f, 2134f))
-    }
-
-    @Test
-    fun add_withPointThenVec_correctlyAddsAndFillsAndDoesntMutateInputs() {
-        val point = MutablePoint(10f, 40f)
-        val vec = MutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.add(point, vec, output)
-
-        assertThat(output).isEqualTo(MutablePoint(15f, 38f))
-        assertThat(point).isEqualTo(MutablePoint(10f, 40f))
-        assertThat(vec).isEqualTo(MutableVec(5f, -2f))
-    }
-
-    @Test
-    fun add_withVecThenPoint_correctlyAddsAndFillsAndDoesntMutateInputs() {
-        val point = MutablePoint(10f, 40f)
-        val vec = MutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.add(vec, point, output)
-
-        assertThat(output).isEqualTo(MutablePoint(15f, 38f))
-        assertThat(point).isEqualTo(MutablePoint(10f, 40f))
-        assertThat(vec).isEqualTo(MutableVec(5f, -2f))
-    }
-
-    @Test
-    fun subtract_pointMinusVec_correctlySubtractsAndFillsAndDoesntMutateInputs() {
-        val point = MutablePoint(10f, 40f)
-        val vec = MutableVec(5f, -2f)
-        val output = MutablePoint()
-
-        Point.subtract(point, vec, output)
-
-        assertThat(output).isEqualTo(MutablePoint(5f, 42f))
-        assertThat(point).isEqualTo(MutablePoint(10f, 40f))
-        assertThat(vec).isEqualTo(MutableVec(5f, -2f))
-    }
-
-    @Test
-    fun subtract_pointMinusPoint_correctlySubtractsAndFillsAndDoesntMutateInputs() {
-        val lhsPoint = MutablePoint(10f, 40f)
-        val rhsPoint = MutablePoint(5f, -2f)
-        val output = MutableVec()
-
-        Point.subtract(lhsPoint, rhsPoint, output)
-
-        assertThat(output).isEqualTo(MutableVec(5f, 42f))
-        assertThat(lhsPoint).isEqualTo(MutablePoint(10f, 40f))
-        assertThat(rhsPoint).isEqualTo(MutablePoint(5f, -2f))
-    }
-}
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableVecTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableVecTest.kt
index afa1451..ce354cc 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableVecTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/MutableVecTest.kt
@@ -36,9 +36,9 @@
     @Test
     fun equals_whenDifferentType_returnsFalse() {
         val vec = MutableVec(1f, 2f)
-        val point = MutablePoint(1f, 2f)
+        val segment = MutableSegment(ImmutableVec(1f, 2f), ImmutableVec(3f, 4f))
 
-        assertThat(vec).isNotEqualTo(point)
+        assertThat(vec).isNotEqualTo(segment)
     }
 
     @Test
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ParallelogramInterfaceTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ParallelogramInterfaceTest.kt
index f9982d6..89647f2 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ParallelogramInterfaceTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/ParallelogramInterfaceTest.kt
@@ -35,11 +35,11 @@
                 assertThat(normalizedHeight).isEqualTo(expectedHeight)
                 assertThat(normalizedRotation).isWithin(tolerance).of(expectedRotation)
                 TestParallelogram(
-                    ImmutablePoint(0f, 0f),
+                    ImmutableVec(0f, 0f),
                     expectedWidth,
                     expectedHeight,
                     expectedRotation,
-                    0f,
+                    0f
                 )
             }
         Parallelogram.normalizeAndRun(
@@ -61,11 +61,11 @@
                 assertThat(normalizedHeight).isEqualTo(expectedHeight)
                 assertThat(normalizedRotation).isWithin(tolerance).of(expectedRotation)
                 TestParallelogram(
-                    ImmutablePoint(0f, 0f),
+                    ImmutableVec(0f, 0f),
                     expectedWidth,
                     expectedHeight,
                     expectedRotation,
-                    0f,
+                    0f
                 )
             }
 
@@ -90,7 +90,7 @@
     }
 
     private class TestParallelogram(
-        override val center: ImmutablePoint,
+        override val center: ImmutableVec,
         override val width: Float,
         override val height: Float,
         override val rotation: Float,
@@ -98,7 +98,7 @@
     ) : Parallelogram {
         companion object {
             val makeTestParallelogram = { w: Float, h: Float, r: Float ->
-                TestParallelogram(ImmutablePoint(0f, 0f), w, h, r, 0f)
+                TestParallelogram(ImmutableVec(0f, 0f), w, h, r, 0f)
             }
         }
     }
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PartitionedMeshTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PartitionedMeshTest.kt
new file mode 100644
index 0000000..682b88d
--- /dev/null
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PartitionedMeshTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.ink.geometry
+
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class PartitionedMeshTest {
+
+    @Test
+    fun bounds_shouldBeEmpty() {
+        val partitionedMesh = PartitionedMesh()
+
+        assertThat(partitionedMesh.bounds).isNull()
+    }
+
+    @Test
+    fun renderGroupCount_whenEmptyShape_shouldBeZero() {
+        val partitionedMesh = PartitionedMesh()
+
+        assertThat(partitionedMesh.renderGroupCount).isEqualTo(0)
+    }
+
+    @Test
+    fun outlineCount_whenEmptyShape_shouldThrow() {
+        val partitionedMesh = PartitionedMesh()
+
+        assertFailsWith { partitionedMesh.outlineCount(-1) }
+        assertFailsWith { partitionedMesh.outlineCount(0) }
+        assertFailsWith { partitionedMesh.outlineCount(1) }
+    }
+
+    @Test
+    fun outlineVertexCount_whenEmptyShape_shouldThrow() {
+        val partitionedMesh = PartitionedMesh()
+
+        assertFailsWith { partitionedMesh.outlineVertexCount(-1, 0) }
+        assertFailsWith { partitionedMesh.outlineVertexCount(0, 0) }
+        assertFailsWith { partitionedMesh.outlineVertexCount(1, 0) }
+    }
+
+    @Test
+    fun populateOutlinePosition_whenEmptyShape_shouldThrow() {
+        val partitionedMesh = PartitionedMesh()
+
+        assertFailsWith {
+            partitionedMesh.populateOutlinePosition(-1, 0, 0, MutableVec())
+        }
+        assertFailsWith {
+            partitionedMesh.populateOutlinePosition(0, 0, 0, MutableVec())
+        }
+        assertFailsWith {
+            partitionedMesh.populateOutlinePosition(1, 0, 0, MutableVec())
+        }
+    }
+
+    @Test
+    fun toString_returnsAString() {
+        val string = PartitionedMesh().toString()
+
+        // Not elaborate checks - this test mainly exists to ensure that toString doesn't crash.
+        assertThat(string).contains("PartitionedMesh")
+        assertThat(string).contains("bounds")
+        assertThat(string).contains("meshes")
+        assertThat(string).contains("nativeAddress")
+    }
+}
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PointTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PointTest.kt
deleted file mode 100644
index e6e4eef..0000000
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/PointTest.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2024 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.ink.geometry
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class PointTest {
-
-    @Test
-    fun isAlmostEqual_whenNoToleranceGiven_returnsCorrectValue() {
-        val point = ImmutablePoint(1f, 2f)
-
-        assertThat(point.isAlmostEqual(point)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1f, 2f))).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.00001f, 1.99999f))).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1f, 1.99f))).isFalse()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.01f, 2f))).isFalse()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.01f, 1.99f))).isFalse()
-    }
-
-    @Test
-    fun isAlmostEqual_withToleranceGiven_returnsCorrectValue() {
-        val point = ImmutablePoint(1f, 2f)
-
-        assertThat(point.isAlmostEqual(point, tolerance = 0.00000001f)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1f, 2f), tolerance = 0.00000001f)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.00001f, 1.99999f), tolerance = 0.000001f))
-            .isFalse()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1f, 1.99f), tolerance = 0.02f)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.01f, 2f), tolerance = 0.02f)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(1.01f, 1.99f), tolerance = 0.02f)).isTrue()
-        assertThat(point.isAlmostEqual(ImmutablePoint(2.5f, 0.5f), tolerance = 2f)).isTrue()
-    }
-
-    @Test
-    fun isAlmostEqual_whenSameInterface_returnsTrue() {
-        val point = MutablePoint(1f, 2f)
-        val other = ImmutablePoint(0.99999f, 2.00001f)
-        assertThat(point.isAlmostEqual(other)).isTrue()
-    }
-}
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/SegmentTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/SegmentTest.kt
index 48403e1..850388d 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/SegmentTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/SegmentTest.kt
@@ -347,9 +347,9 @@
         val segment1 = ImmutableSegment(ImmutableVec(-1f, 2f), ImmutableVec(0f, 0f))
 
         assertThat(segment0.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 1f), ImmutablePoint(5f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(1f, 1f), ImmutableVec(5f, 2f)))
         assertThat(segment1.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, 0f), ImmutablePoint(0f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-1f, 0f), ImmutableVec(0f, 2f)))
     }
 
     @Test
@@ -358,9 +358,9 @@
         val segment1 = ImmutableSegment(ImmutableVec(0f, 0f), ImmutableVec(0f, 0f))
 
         assertThat(segment0.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(3f, 2f), ImmutablePoint(3f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(3f, 2f), ImmutableVec(3f, 2f)))
         assertThat(segment1.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(0f, 0f), ImmutablePoint(0f, 0f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(0f, 0f), ImmutableVec(0f, 0f)))
     }
 
     @Test
@@ -375,11 +375,11 @@
 
         assertThat(box0)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1f, 1f), ImmutablePoint(5f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1f, 1f), ImmutableVec(5f, 2f))
             )
         assertThat(box1)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-1f, 0f), ImmutablePoint(0f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-1f, 0f), ImmutableVec(0f, 2f))
             )
     }
 
@@ -395,11 +395,11 @@
 
         assertThat(box0)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(3f, 2f), ImmutablePoint(3f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(3f, 2f), ImmutableVec(3f, 2f))
             )
         assertThat(box1)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(0f, 0f), ImmutablePoint(0f, 0f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(0f, 0f), ImmutableVec(0f, 0f))
             )
     }
 
diff --git a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/TriangleTest.kt b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/TriangleTest.kt
index 0309d82..a6daeba 100644
--- a/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/TriangleTest.kt
+++ b/ink/ink-geometry/src/jvmAndroidTest/kotlin/androidx/ink/geometry/TriangleTest.kt
@@ -69,13 +69,13 @@
             ImmutableTriangle(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f), ImmutableVec(5f, 2f))
 
         assertThat(triangle0.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(1f, 1f), ImmutablePoint(5f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(1f, 1f), ImmutableVec(5f, 2f)))
         assertThat(triangle1.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, -2f), ImmutablePoint(1f, 0f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-1f, -2f), ImmutableVec(1f, 0f)))
         assertThat(triangle2.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(-2f, 1f), ImmutablePoint(0f, 3f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-2f, 1f), ImmutableVec(0f, 3f)))
         assertThat(triangle3.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(5f, 2f), ImmutablePoint(5f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f)))
     }
 
     @Test
@@ -90,13 +90,13 @@
             ImmutableTriangle(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f), ImmutableVec(5f, 2f))
 
         assertThat(triangle0.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(2f, 2f), ImmutablePoint(5f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(2f, 2f), ImmutableVec(5f, 2f)))
         assertThat(triangle1.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(-1f, -2f), ImmutablePoint(1f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-1f, -2f), ImmutableVec(1f, 2f)))
         assertThat(triangle2.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(-2f, 1f), ImmutablePoint(0f, 3f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(-2f, 1f), ImmutableVec(0f, 3f)))
         assertThat(triangle3.boundingBox)
-            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutablePoint(5f, 2f), ImmutablePoint(5f, 2f)))
+            .isEqualTo(ImmutableBox.fromTwoPoints(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f)))
     }
 
     @Test
@@ -121,19 +121,19 @@
 
         assertThat(box0)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(1f, 1f), ImmutablePoint(5f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(1f, 1f), ImmutableVec(5f, 2f))
             )
         assertThat(box1)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-1f, -2f), ImmutablePoint(1f, 0f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-1f, -2f), ImmutableVec(1f, 0f))
             )
         assertThat(box2)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-2f, 1f), ImmutablePoint(0f, 3f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-2f, 1f), ImmutableVec(0f, 3f))
             )
         assertThat(box3)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(5f, 2f), ImmutablePoint(5f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f))
             )
     }
 
@@ -159,19 +159,19 @@
 
         assertThat(box0)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(2f, 2f), ImmutablePoint(5f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(2f, 2f), ImmutableVec(5f, 2f))
             )
         assertThat(box1)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-1f, -2f), ImmutablePoint(1f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-1f, -2f), ImmutableVec(1f, 2f))
             )
         assertThat(box2)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(-2f, 1f), ImmutablePoint(0f, 3f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(-2f, 1f), ImmutableVec(0f, 3f))
             )
         assertThat(box3)
             .isEqualTo(
-                MutableBox().fillFromTwoPoints(ImmutablePoint(5f, 2f), ImmutablePoint(5f, 2f))
+                MutableBox().populateFromTwoPoints(ImmutableVec(5f, 2f), ImmutableVec(5f, 2f))
             )
     }
 }
diff --git a/libraryversions.toml b/libraryversions.toml
index 74ef3ba..85d5aab 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -3,7 +3,7 @@
 ANNOTATION = "1.9.0-alpha02"
 ANNOTATION_EXPERIMENTAL = "1.5.0-alpha01"
 APPCOMPAT = "1.8.0-alpha01"
-APPSEARCH = "1.1.0-alpha04"
+APPSEARCH = "1.1.0-alpha05"
 ARCH_CORE = "2.3.0-alpha01"
 ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
 AUTOFILL = "1.3.0-alpha02"
@@ -24,9 +24,9 @@
 COMPOSE_MATERIAL3_ADAPTIVE = "1.1.0-alpha01"
 COMPOSE_MATERIAL3_COMMON = "1.0.0-alpha01"
 COMPOSE_RUNTIME_TRACING = "1.0.0-beta01"
-CONSTRAINTLAYOUT = "2.2.0-alpha14"
-CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha14"
-CONSTRAINTLAYOUT_CORE = "1.1.0-alpha14"
+CONSTRAINTLAYOUT = "2.2.0-beta01"
+CONSTRAINTLAYOUT_COMPOSE = "1.1.0-beta01"
+CONSTRAINTLAYOUT_CORE = "1.1.0-beta01"
 CONTENTPAGER = "1.1.0-alpha01"
 COORDINATORLAYOUT = "1.3.0-alpha02"
 CORE = "1.15.0-alpha02"
@@ -109,7 +109,7 @@
 PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha14"
 PRIVACYSANDBOX_TOOLS = "1.0.0-alpha09"
 PRIVACYSANDBOX_UI = "1.0.0-alpha09"
-PROFILEINSTALLER = "1.4.0-beta01"
+PROFILEINSTALLER = "1.4.0-rc01"
 RECOMMENDATION = "1.1.0-alpha01"
 RECYCLERVIEW = "1.4.0-beta01"
 RECYCLERVIEW_SELECTION = "1.2.0-alpha02"
@@ -134,7 +134,7 @@
 SQLITE = "2.5.0-alpha07"
 SQLITE_INSPECTOR = "2.1.0-alpha01"
 STABLE_AIDL = "1.0.0-alpha01"
-STARTUP = "1.2.0-beta01"
+STARTUP = "1.2.0-rc01"
 SWIPEREFRESHLAYOUT = "1.2.0-alpha01"
 TESTEXT = "1.0.0-alpha03"
 TESTSCREENSHOT = "1.0.0-alpha01"
@@ -168,7 +168,7 @@
 WEAR_WATCHFACE = "1.3.0-alpha03"
 WEBKIT = "1.12.0-beta01"
 # Adding a comment to prevent merge conflicts for Window artifact
-WINDOW = "1.4.0-alpha01"
+WINDOW = "1.4.0-alpha02"
 WINDOW_EXTENSIONS = "1.4.0-beta01"
 WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
 WINDOW_SIDECAR = "1.0.0-rc01"
diff --git a/mediarouter/mediarouter/src/main/res/values-in/strings.xml b/mediarouter/mediarouter/src/main/res/values-in/strings.xml
index a646d3d..87abce1 100644
--- a/mediarouter/mediarouter/src/main/res/values-in/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-in/strings.xml
@@ -25,7 +25,7 @@
     "Transmisikan ke"
     "Mencari perangkat"
     "Mencari perangkat..."
-    "Putuskan koneksi"
+    "Berhenti hubungkan"
     "Hentikan transmisi"
     "Tutup"
     "Putar"
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
index c2cf3c6..df00b37 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
@@ -147,10 +147,14 @@
             return Class.forName(className)
         } catch (_: ClassNotFoundException) {}
     }
-    throw IllegalArgumentException(
+    var errorMsg =
         "Cannot find class with name \"$serialName\". Ensure that the " +
             "serialName for this argument is the default fully qualified name"
-    )
+    if (kind is SerialKind.ENUM) {
+        errorMsg =
+            "$errorMsg.\nIf the build is minified, try annotating the Enum class with \"androidx.annotation.Keep\" to ensure the Enum is not removed."
+    }
+    throw IllegalArgumentException(errorMsg)
 }
 
 /**
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
index 0b7db49..f395dd1 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
@@ -825,7 +825,9 @@
         assertThat(exception.message)
             .isEqualTo(
                 "Cannot find class with name \"MyCustomSerialName\". Ensure that the " +
-                    "serialName for this argument is the default fully qualified name"
+                    "serialName for this argument is the default fully qualified name." +
+                    "\nIf the build is minified, try annotating the Enum class " +
+                    "with \"androidx.annotation.Keep\" to ensure the Enum is not removed."
             )
     }
 
diff --git a/pdf/pdf-viewer/src/main/res/values-af/strings.xml b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
index 19b1121c..65776f5 100644
--- a/pdf/pdf-viewer/src/main/res/values-af/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-af/strings.xml
@@ -47,6 +47,9 @@
     "bladsy %1$d tot %2$d van %3$d"
     "Prent: %1$s"
     "Soek in lêer"
+    "Vorige"
+    "Volgende"
+    "Maak toe"
     "Geen passende resultate nie."
     "%1$d/%2$d"
     "Wysig lêer"
diff --git a/pdf/pdf-viewer/src/main/res/values-am/strings.xml b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
index 59e6e04..f286f6e 100644
--- a/pdf/pdf-viewer/src/main/res/values-am/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-am/strings.xml
@@ -47,6 +47,9 @@
     "%1$d እስከ %2$d ገጾች ከ%3$d"
     "ምስል፦ %1$s"
     "ፋይል ውስጥ ያግኙ"
+    "ቀዳሚ"
+    "ቀጣይ"
+    "ዝጋ"
     "ምንም ተመሳሳዮች አልተገኙም።"
     "%1$d / %2$d"
     "ፋይል አርትዕ"
diff --git a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
index 8f89292..e31d42c 100644
--- a/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ar/strings.xml
@@ -47,6 +47,9 @@
     "الصفحات من %1$d إلى %2$d من إجمالي %3$d"
     "صورة: %1$s"
     "البحث في الملف"
+    "السابق"
+    "التالي"
+    "إغلاق"
     "لم يتم العثور على نتائج مطابِقة."
     "‫%1$d من أصل %2$d"
     "تعديل الملف"
diff --git a/pdf/pdf-viewer/src/main/res/values-as/strings.xml b/pdf/pdf-viewer/src/main/res/values-as/strings.xml
index 3de154e..ffbfad0 100644
--- a/pdf/pdf-viewer/src/main/res/values-as/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-as/strings.xml
@@ -47,6 +47,9 @@
     "%3$d খন পৃষ্ঠাৰ %1$dৰ পৰা %2$dলৈ থকা পৃষ্ঠাসমূহ"
     "প্ৰতিচ্ছবি: %1$s"
     "ফাইলত বিচাৰক"
+    "পূৰ্বৱৰ্তী"
+    "পৰৱৰ্তী"
+    "বন্ধ কৰক"
     "কোনো মিল পোৱা নগ’ল।"
     "%1$d / %2$d"
     "ফাইল সম্পাদনা কৰক"
diff --git a/pdf/pdf-viewer/src/main/res/values-az/strings.xml b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
index 4293921..a286444 100644
--- a/pdf/pdf-viewer/src/main/res/values-az/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-az/strings.xml
@@ -47,6 +47,9 @@
     "%3$d səhifənin %1$d-%2$d səhifələri"
     "Şəkil: %1$s"
     "Faylda tapın"
+    "Əvvəlki"
+    "Növbəti"
+    "Bağlayın"
     "Uyğunluq tapılmadı."
     "%1$d / %2$d"
     "Faylı redaktə edin"
diff --git a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
index 2723618..8888361 100644
--- a/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-b+sr+Latn/strings.xml
@@ -47,6 +47,9 @@
     "stranice %1$d. do %2$d. od %3$d"
     "Slika: %1$s"
     "Pronađite u fajlu"
+    "Prethodno"
+    "Dalje"
+    "Zatvori"
     "Nije pronađeno nijedno podudaranje."
     "%1$d/%2$d"
     "Izmeni fajl"
diff --git a/pdf/pdf-viewer/src/main/res/values-be/strings.xml b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
index 179a2e7..fb6f15e 100644
--- a/pdf/pdf-viewer/src/main/res/values-be/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-be/strings.xml
@@ -47,6 +47,9 @@
     "старонкі з %1$d па %2$d (усяго %3$d)"
     "Відарыс: %1$s"
     "Знайсці ў файле"
+    "Назад"
+    "Далей"
+    "Закрыць"
     "Супадзенні не знойдзены."
     "%1$d з %2$d"
     "Рэдагаваць файл"
diff --git a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
index 67b6be7..25db523 100644
--- a/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bg/strings.xml
@@ -47,6 +47,9 @@
     "страници %1$d до %2$d от %3$d"
     "Изображение: %1$s"
     "Търсете във файла"
+    "Назад"
+    "Напред"
+    "Затваряне"
     "Няма намерени съответствия."
     "%1$d/%2$d"
     "Редактиране на файла"
diff --git a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
index 7b5287a..94bf49d 100644
--- a/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bn/strings.xml
@@ -47,6 +47,9 @@
     "%3$dটির মধ্যে %1$d থেকে %2$d"
     "ছবি: %1$s"
     "ফাইলে খুঁজুন"
+    "পূর্ববর্তী"
+    "পরবর্তী"
+    "বন্ধ করুন"
     "কোনও মিল খুঁজে পাওয়া যায়নি।"
     "%1$d / %2$d"
     "ফাইল এডিট করুন"
diff --git a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
index 4944bfa..e204ced 100644
--- a/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-bs/strings.xml
@@ -47,6 +47,9 @@
     "od %1$d. do %2$d. stranice od %3$d"
     "Slika: %1$s"
     "Pronađi u fajlu"
+    "Nazad"
+    "Naprijed"
+    "Zatvaranje"
     "Nije pronađeno nijedno podudaranje."
     "%1$d/%2$d"
     "Uredite fajl"
diff --git a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
index b8b2b4c..a86bb26 100644
--- a/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ca/strings.xml
@@ -47,6 +47,9 @@
     "pàgines %1$d a %2$d de %3$d"
     "Imatge: %1$s"
     "Cerca al fitxer"
+    "Anterior"
+    "Següent"
+    "Tanca"
     "No s\'han trobat coincidències."
     "%1$d/%2$d"
     "Edita el fitxer"
diff --git a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
index 395aa47..7f45912 100644
--- a/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-cs/strings.xml
@@ -47,6 +47,9 @@
     "stránky %1$d%2$d%3$d"
     "Obrázek: %1$s"
     "Najít v souboru"
+    "Předchozí"
+    "Další"
+    "Zavřít"
     "Nebyly nalezeny žádné shody."
     "%1$d/%2$d"
     "Upravit soubor"
diff --git a/pdf/pdf-viewer/src/main/res/values-da/strings.xml b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
index 9b95de8..a91e7f3 100644
--- a/pdf/pdf-viewer/src/main/res/values-da/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-da/strings.xml
@@ -47,6 +47,9 @@
     "side %1$d til %2$d af %3$d"
     "Billede: %1$s"
     "Søg i fil"
+    "Forrige"
+    "Næste"
+    "Luk"
     "Der blev ikke fundet noget match."
     "%1$d/%2$d"
     "Rediger fil"
diff --git a/pdf/pdf-viewer/src/main/res/values-de/strings.xml b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
index 1ac353e..ed57aad 100644
--- a/pdf/pdf-viewer/src/main/res/values-de/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-de/strings.xml
@@ -47,6 +47,9 @@
     "Seiten %1$d bis %2$d von %3$d"
     "Bild: %1$s"
     "In Datei suchen"
+    "Zurück"
+    "Weiter"
+    "Schließen"
     "Keine Übereinstimmungen gefunden."
     "%1$d/%2$d"
     "Datei bearbeiten"
diff --git a/pdf/pdf-viewer/src/main/res/values-el/strings.xml b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
index 74b6dfa..3bd9d38 100644
--- a/pdf/pdf-viewer/src/main/res/values-el/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-el/strings.xml
@@ -47,6 +47,9 @@
     "σελίδες %1$d έως %2$d από %3$d"
     "Εικόνα: %1$s"
     "Εύρεση σε αρχείο"
+    "Προηγούμενο"
+    "Επόμενο"
+    "Κλείσιμο"
     "Δεν εντοπίστηκαν αντιστοιχίσεις."
     "%1$d/%2$d"
     "Επεξεργασία αρχείου"
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
index 609570b..a94dd56 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rAU/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d to %2$d of %3$d"
     "Image: %1$s"
     "Find in file"
+    "Previous"
+    "Next"
+    "Close"
     "No matches found."
     "%1$d/%2$d"
     "Edit file"
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
index 3be5a4f..bf5372f 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rCA/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d to %2$d of %3$d"
     "Image: %1$s"
     "Find in file"
+    "Previous"
+    "Next"
+    "Close"
     "No matches found."
     "%1$d / %2$d"
     "Edit file"
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
index 609570b..a94dd56 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rGB/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d to %2$d of %3$d"
     "Image: %1$s"
     "Find in file"
+    "Previous"
+    "Next"
+    "Close"
     "No matches found."
     "%1$d/%2$d"
     "Edit file"
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
index 609570b..a94dd56 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rIN/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d to %2$d of %3$d"
     "Image: %1$s"
     "Find in file"
+    "Previous"
+    "Next"
+    "Close"
     "No matches found."
     "%1$d/%2$d"
     "Edit file"
diff --git a/pdf/pdf-viewer/src/main/res/values-en-rXC/strings.xml b/pdf/pdf-viewer/src/main/res/values-en-rXC/strings.xml
index c63cb2d..f5a95da 100644
--- a/pdf/pdf-viewer/src/main/res/values-en-rXC/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-en-rXC/strings.xml
@@ -47,6 +47,9 @@
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎pages ‎‏‎‎‏‏‎%1$d‎‏‎‎‏‏‏‎ to ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎%3$d‎‏‎‎‏‏‏‎‎‏‎‎‏‎"
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎Image: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎"
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎Find in file‎‏‎‎‏‎"
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎Previous‎‏‎‎‏‎"
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‎‏‎Next‎‏‎‎‏‎"
+    "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‎‏‏‎Close‎‏‎‎‏‎"
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎No matches found.‎‏‎‎‏‎"
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎%1$d‎‏‎‎‏‏‏‎ / ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎‎‏‎‎‏‎"
     "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎Edit file‎‏‎‎‏‎"
diff --git a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
index dbe8fae..6bab2a8b 100644
--- a/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es-rUS/strings.xml
@@ -47,6 +47,12 @@
     "páginas %1$d a %2$d de %3$d"
     "Imagen: %1$s"
     "Buscar en el archivo"
+    
+    
+    
+    
+    
+    
     "No hay coincidencias."
     "%1$d/%2$d"
     "Editar el archivo"
diff --git a/pdf/pdf-viewer/src/main/res/values-es/strings.xml b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
index fa7f116..2aaec0e 100644
--- a/pdf/pdf-viewer/src/main/res/values-es/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-es/strings.xml
@@ -47,6 +47,12 @@
     "páginas %1$d a %2$d de %3$d"
     "Imagen: %1$s"
     "Buscar en el archivo"
+    
+    
+    
+    
+    
+    
     "No se han encontrado coincidencias."
     "%1$d/%2$d"
     "Editar archivo"
diff --git a/pdf/pdf-viewer/src/main/res/values-et/strings.xml b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
index 4b085c6..685a80c 100644
--- a/pdf/pdf-viewer/src/main/res/values-et/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-et/strings.xml
@@ -47,6 +47,9 @@
     "lk %1$d%2$d/%3$d-st"
     "Pilt: %1$s"
     "Otsige failist"
+    "Eelmine"
+    "Järgmine"
+    "Sule"
     "Vasteid ei leitud."
     "%1$d/%2$d"
     "Faili muutmine"
diff --git a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
index 458acf0..f9d27fb 100644
--- a/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-eu/strings.xml
@@ -47,6 +47,9 @@
     "%1$d eta %2$d bitarteko orriak, guztira %3$d"
     "Irudia: %1$s"
     "Bilatu fitxategia"
+    "Aurrekoa"
+    "Hurrengoa"
+    "Itxi"
     "Ez da aurkitu emaitzarik."
     "%1$d/%2$d"
     "Editatu fitxategia"
diff --git a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
index 54bf7e7..aa516d3 100644
--- a/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fa/strings.xml
@@ -47,6 +47,9 @@
     "صفحه‌های %1$d تا %2$d از %3$d"
     "تصویر: %1$s"
     "پیدا کردن در فایل"
+    "قبلی"
+    "بعدی"
+    "بستن"
     "مورد منطبقی یافت نشد."
     "%1$d / %2$d"
     "ویرایش فایل"
diff --git a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
index 0b03cc8e..d3e2c81 100644
--- a/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fi/strings.xml
@@ -47,6 +47,9 @@
     "sivut %1$d%2$d/%3$d"
     "Kuva: %1$s"
     "Etsi tiedostosta"
+    "Edellinen"
+    "Seuraava"
+    "Sulje"
     "Osumia ei löytynyt."
     "%1$d/%2$d"
     "Muokkaa tiedostoa"
diff --git a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
index ffa53ba..ad4332a 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr-rCA/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d à %2$d sur %3$d"
     "Image : %1$s"
     "Trouver dans fichier"
+    "Précédent"
+    "Suivant"
+    "Fermer"
     "Aucune correspondance."
     "%1$d/%2$d"
     "Modifier le fichier"
diff --git a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
index fd1ee39..2b73672 100644
--- a/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-fr/strings.xml
@@ -47,6 +47,9 @@
     "pages %1$d à %2$d sur %3$d"
     "Image : %1$s"
     "Rechercher dans fichier"
+    "Précédent"
+    "Suivant"
+    "Fermer"
     "Aucune correspondance."
     "%1$d/%2$d"
     "Modifier le fichier"
diff --git a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
index 5965cb5..8a41d20 100644
--- a/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gl/strings.xml
@@ -47,6 +47,9 @@
     "páxinas da %1$d á %2$d dun total de %3$d"
     "Imaxe: %1$s"
     "Busca no ficheiro"
+    "Anterior"
+    "Seguinte"
+    "Pechar"
     "Non se atopou ningunha coincidencia."
     "%1$d/%2$d"
     "Editar o ficheiro"
diff --git a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
index e8bb6cf..8a91196 100644
--- a/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-gu/strings.xml
@@ -47,6 +47,9 @@
     "%3$dમાંથી પેજ %1$dથી %2$d"
     "છબી: %1$s"
     "ફાઇલમાં શોધો"
+    "પાછળ"
+    "આગળ"
+    "બંધ કરો"
     "કોઈ મેળ મળ્યો નથી."
     "%1$d / %2$d"
     "ફાઇલમાં ફેરફાર કરો"
diff --git a/pdf/pdf-viewer/src/main/res/values-hi/strings.xml b/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
index 5d44d0d..0d55f5d 100644
--- a/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hi/strings.xml
@@ -47,6 +47,9 @@
     "%3$d में से %1$d से %2$d पेज"
     "इमेज: %1$s"
     "फ़ाइल में खोजें"
+    "पीछे जाएं"
+    "आगे बढ़ें"
+    "बंद करें"
     "इससे मिलता-जुलता कोई नतीजा नहीं मिला."
     "%1$d / %2$d"
     "फ़ाइल में बदलाव करें"
diff --git a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
index a0c4be4..2b67621 100644
--- a/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hr/strings.xml
@@ -47,6 +47,9 @@
     "stranice od %1$d do %2$d od ukupno %3$d"
     "Slika: %1$s"
     "Pronađi u datoteci"
+    "Prethodno"
+    "Sljedeće"
+    "Zatvori"
     "Nisu pronađena podudaranja."
     "%1$d/%2$d"
     "Uređivanje datoteke"
diff --git a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
index 41020ca..70d3f7d 100644
--- a/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hu/strings.xml
@@ -47,6 +47,9 @@
     "%3$d/%1$d%2$d. oldal"
     "Kép: %1$s"
     "Keresés a fájlban"
+    "Előző"
+    "Következő"
+    "Bezárás"
     "Nincs találat."
     "%2$d/%1$d."
     "Fájl szerkesztése"
diff --git a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
index 2e482a1..bba91ac 100644
--- a/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-hy/strings.xml
@@ -47,6 +47,9 @@
     "էջ %1$d%2$d՝ %3$d-ից"
     "Պատկեր՝ %1$s"
     "Գտեք ֆայլում"
+    "Նախորդը"
+    "Հաջորդը"
+    "Փակել"
     "Համընկնումներ չեն հայտնաբերվել։"
     "%1$d/%2$d"
     "Փոփոխել ֆայլը"
diff --git a/pdf/pdf-viewer/src/main/res/values-in/strings.xml b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
index 0e9397c..0ed5ba6 100644
--- a/pdf/pdf-viewer/src/main/res/values-in/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-in/strings.xml
@@ -47,6 +47,9 @@
     "halaman %1$d sampai %2$d dari %3$d"
     "Gambar: %1$s"
     "Cari dalam file"
+    "Sebelumnya"
+    "Berikutnya"
+    "Tutup"
     "Tidak ada yang cocok."
     "%1$d/%2$d"
     "Edit file"
diff --git a/pdf/pdf-viewer/src/main/res/values-is/strings.xml b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
index 1a2f9ff..f9b8a81 100644
--- a/pdf/pdf-viewer/src/main/res/values-is/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-is/strings.xml
@@ -47,6 +47,9 @@
     "síður %1$d til %2$d af %3$d"
     "Mynd: %1$s"
     "Leita í skrá"
+    "Fyrri"
+    "Næsta"
+    "Loka"
     "Ekkert fannst."
     "%1$d / %2$d"
     "Breyta skrá"
diff --git a/pdf/pdf-viewer/src/main/res/values-it/strings.xml b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
index 3025646..c96299a 100644
--- a/pdf/pdf-viewer/src/main/res/values-it/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-it/strings.xml
@@ -47,6 +47,9 @@
     "pagine da %1$d a %2$d di %3$d"
     "Immagine: %1$s"
     "Trova nel file"
+    "Indietro"
+    "Avanti"
+    "Chiudi"
     "Nessuna corrispondenza."
     "%1$d/%2$d"
     "Modifica file"
diff --git a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
index 0d21739..7e45469 100644
--- a/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-iw/strings.xml
@@ -47,6 +47,9 @@
     "דפים %1$d עד %2$d מתוך %3$d"
     "תמונה: %1$s"
     "חיפוש בקובץ"
+    "הקודם"
+    "הבא"
+    "סגירה"
     "לא נמצאו התאמות."
     "‫%1$d מתוך %2$d"
     "עריכת הקובץ"
diff --git a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
index c5db90d..e151e77 100644
--- a/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ja/strings.xml
@@ -47,6 +47,9 @@
     "%1$d%2$d/%3$d ページ"
     "画像: %1$s"
     "ファイル内を検索"
+    "前へ"
+    "次へ"
+    "閉じる"
     "一致する項目は見つかりませんでした。"
     "%1$d / %2$d"
     "ファイルを編集"
diff --git a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
index cc30d31..93298e6 100644
--- a/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ka/strings.xml
@@ -47,6 +47,9 @@
     "%1$d-%2$d გვერდები %3$d-დან"
     "სურათი: %1$s"
     "ფაილში ძებნა"
+    "წინა"
+    "შემდეგი"
+    "დახურვა"
     "შესატყვისი ვერ მოიძებნა."
     "%1$d / %2$d"
     "ფაილის რედაქტირება"
diff --git a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
index 84b91ca..f5e8e7b 100644
--- a/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kk/strings.xml
@@ -47,6 +47,9 @@
     "Бет: %1$d-%2$d/%3$d"
     "Сурет: %1$s."
     "Файлдан табу"
+    "Алдыңғы"
+    "Келесі"
+    "Жабу"
     "Ешқандай сәйкестік табылмады."
     "%1$d/%2$d"
     "Файлды өңдеу"
diff --git a/pdf/pdf-viewer/src/main/res/values-km/strings.xml b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
index 2e9bf3b..4ff77d1 100644
--- a/pdf/pdf-viewer/src/main/res/values-km/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-km/strings.xml
@@ -47,6 +47,9 @@
     "ទំព័រទី %1$d ដល់ %2$d នៃ %3$d"
     "រូបភាព៖ %1$s"
     "ស្វែងរកនៅក្នុងឯកសារ"
+    "មុន"
+    "បន្ទាប់"
+    "បិទ"
     "រក​មិន​ឃើញ​អ្វីដែល​ត្រូវ​គ្នាទេ។"
     "%1$d / %2$d"
     "កែ​ឯកសារ"
diff --git a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
index 00aa9bb..ee915f0 100644
--- a/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-kn/strings.xml
@@ -47,6 +47,9 @@
     "%1$d ನಿಂದ %2$d ವರೆಗಿನ %3$d ಪುಟಗಳು"
     "ಚಿತ್ರ: %1$s"
     "ಫೈಲ್‌ನಲ್ಲಿ ಹುಡುಕಿ"
+    "ಹಿಂದಿನದು"
+    "ಮುಂದಿನದು"
+    "ಮುಚ್ಚಿರಿ"
     "ಯಾವುದೇ ಹೊಂದಾಣಿಕೆಗಳು ಕಂಡುಬಂದಿಲ್ಲ."
     "%1$d / %2$d"
     "ಫೈಲ್ ಎಡಿಟ್‌ ಮಾಡಿ"
diff --git a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
index 8189d99..7489748 100644
--- a/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ko/strings.xml
@@ -47,6 +47,9 @@
     "%3$d페이지 중 %1$d~%2$d페이지"
     "이미지: %1$s"
     "파일에서 찾기"
+    "이전"
+    "다음"
+    "닫기"
     "일치하는 항목이 없습니다."
     "%1$d/%2$d"
     "파일 수정"
diff --git a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
index a0e0558..0e81ff3 100644
--- a/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ky/strings.xml
@@ -47,6 +47,9 @@
     "%3$d ичинен %1$d%2$d-беттер"
     "Сүрөт: %1$s"
     "Файлдан издөө"
+    "Мурунку"
+    "Кийинки"
+    "Жабуу"
     "Эч нерсе табылган жок."
     "%1$d / %2$d"
     "Файлды түзөтүү"
diff --git a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
index 06a320b..8d44326 100644
--- a/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lo/strings.xml
@@ -47,6 +47,9 @@
     "ໜ້າທີ %1$d ຫາ %2$d ຈາກທັງໝົດ %3$d ໜ້າ"
     "ຮູບ: %1$s"
     "ຊອກຫາໃນໄຟລ໌"
+    "ກ່ອນໜ້າ"
+    "ຕໍ່ໄປ"
+    "ປິດ"
     "ບໍ່ພົບຂໍ້ມູນທີ່ກົງກັນ."
     "%1$d / %2$d"
     "ແກ້ໄຂໄຟລ໌"
diff --git a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
index 2d6a562..39dd10a 100644
--- a/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lt/strings.xml
@@ -47,6 +47,9 @@
     "%1$d%2$d psl. iš %3$d"
     "Vaizdas: %1$s"
     "Rasti failą"
+    "Ankstesnis"
+    "Kitas"
+    "Uždaryti"
     "Nerasta atitikčių."
     "%1$d / %2$d"
     "Redaguoti failą"
diff --git a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
index 84afd6d..ab51c3f 100644
--- a/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-lv/strings.xml
@@ -47,6 +47,9 @@
     "%1$d.–%2$d. lapa no %3$d"
     "Attēls: %1$s"
     "Meklēt failā"
+    "Atpakaļ"
+    "Tālāk"
+    "Aizvērt"
     "Nav atrasta neviena atbilstība."
     "%1$d/%2$d"
     "Rediģēt failu"
diff --git a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
index 854802a..45c2e02 100644
--- a/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mk/strings.xml
@@ -47,6 +47,9 @@
     "од страница %1$d до %2$d од %3$d"
     "Слика: %1$s"
     "Најдете во датотека"
+    "Претходно"
+    "Следно"
+    "Затвори"
     "Не се најдени совпаѓања."
     "%1$d/%2$d"
     "Изменете ја датотеката"
diff --git a/pdf/pdf-viewer/src/main/res/values-ml/strings.xml b/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
index 516f0cc..de82566 100644
--- a/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ml/strings.xml
@@ -47,6 +47,9 @@
     "%3$d-ൽ %1$d മുതൽ %2$d വരെയുള്ള പേജുകൾ"
     "ചിത്രം: %1$s"
     "ഫയലിൽ കണ്ടെത്തുക"
+    "മുമ്പത്തേത്"
+    "അടുത്തത്"
+    "അടയ്ക്കുക"
     "പൊരുത്തങ്ങളൊന്നും കണ്ടെത്തിയില്ല."
     "%1$d / %2$d"
     "ഫയൽ എഡിറ്റ് ചെയ്യുക"
diff --git a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
index 65ed1dc..d9843af 100644
--- a/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mn/strings.xml
@@ -47,6 +47,9 @@
     "Нийт %3$d хуудасны %1$d-%2$d-р хуудаснууд"
     "Зураг: %1$s"
     "Файлаас олох"
+    "Өмнөх"
+    "Дараах"
+    "Хаах"
     "Ямар ч таарц олдсонгүй."
     "%1$d / %2$d"
     "Файлыг засах"
diff --git a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
index ae238c2..bbfad97 100644
--- a/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-mr/strings.xml
@@ -47,6 +47,9 @@
     "%3$d पैकी पेज %1$d ते %2$d"
     "इमेज: %1$s"
     "फाइल शोधा"
+    "मागील"
+    "पुढील"
+    "बंद करा"
     "कोणत्‍याही जुळण्या आढळल्या नाहीत."
     "%1$d / %2$d"
     "फाइल संपादित करा"
diff --git a/pdf/pdf-viewer/src/main/res/values-ms/strings.xml b/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
index b42f674..f1a6fd6 100644
--- a/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ms/strings.xml
@@ -47,6 +47,9 @@
     "halaman %1$d hingga %2$d daripada %3$d"
     "Imej: %1$s"
     "Temukan dalam fail"
+    "Sebelumnya"
+    "Seterusnya"
+    "Tutup"
     "Tiada padanan ditemukan."
     "%1$d / %2$d"
     "Edit fail"
diff --git a/pdf/pdf-viewer/src/main/res/values-my/strings.xml b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
index ecaf6e9..f4861f1 100644
--- a/pdf/pdf-viewer/src/main/res/values-my/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-my/strings.xml
@@ -47,6 +47,9 @@
     "စာမျက်နှာ %3$d အနက် %1$d မှ %2$d"
     "ပုံ- %1$s"
     "ဖိုင်တွင် ရှာရန်"
+    "ယခင်"
+    "ရှေ့သို့"
+    "ပိတ်ရန်"
     "ကိုက်ညီမှု မတွေ့ပါ။"
     "%1$d / %2$d"
     "ဖိုင် တည်းဖြတ်ရန်"
diff --git a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
index 9bb458d..5082070 100644
--- a/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nb/strings.xml
@@ -47,6 +47,9 @@
     "side %1$d til %2$d av %3$d"
     "Bilde: %1$s"
     "Finn i filen"
+    "Forrige"
+    "Neste"
+    "Lukk"
     "Fant ingen treff."
     "%1$d/%2$d"
     "Endre filen"
diff --git a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
index 346ef60..ddfecaf 100644
--- a/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ne/strings.xml
@@ -47,6 +47,9 @@
     "%3$d मध्ये %2$d देखि %1$d पेजहरू"
     "फोटो: %1$s"
     "फाइलमा खोज्नुहोस्"
+    "अघिल्लो"
+    "अर्को"
+    "बन्द गर्नुहोस्"
     "मिल्दोजुल्दो परिणाम भेटिएन।"
     "%1$d / %2$d"
     "फाइल सम्पादन गर्नुहोस्"
diff --git a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
index a8a14e9..525ca38 100644
--- a/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-nl/strings.xml
@@ -47,6 +47,9 @@
     "pagina\'s %1$d tot en met %2$d van %3$d"
     "Afbeelding: %1$s"
     "Zoeken in bestand"
+    "Vorige"
+    "Volgende"
+    "Sluiten"
     "Geen overeenkomsten gevonden."
     "%1$d/%2$d"
     "Bestand bewerken"
diff --git a/pdf/pdf-viewer/src/main/res/values-or/strings.xml b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
index 26a54de..4dab39f 100644
--- a/pdf/pdf-viewer/src/main/res/values-or/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-or/strings.xml
@@ -47,6 +47,9 @@
     "%3$d%1$dରୁ %2$d ପୃଷ୍ଠା"
     "ଇମେଜ: %1$s"
     "ଫାଇଲରେ ଖୋଜନ୍ତୁ"
+    "ପୂର୍ବବର୍ତ୍ତୀ"
+    "ପରବର୍ତ୍ତୀ"
+    "ବନ୍ଦ କରନ୍ତୁ"
     "କୌଣସି ମେଳ ମିଳୁ ନାହିଁ।"
     "%1$d / %2$d"
     "ଫାଇଲକୁ ଏଡିଟ କରନ୍ତୁ"
diff --git a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
index 876f5ae..bdbe170 100644
--- a/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pa/strings.xml
@@ -47,6 +47,9 @@
     "ਕੁੱਲ %3$d ਵਿੱਚੋਂ %1$d ਤੋਂ %2$d ਤੱਕ ਪੰਨੇ"
     "ਚਿੱਤਰ: %1$s"
     "ਫ਼ਾਈਲ ਵਿੱਚ ਲੱਭੋ"
+    "ਪਿੱਛੇ"
+    "ਅੱਗੇ"
+    "ਬੰਦ ਕਰੋ"
     "ਕੋਈ ਮੇਲ ਨਹੀਂ ਮਿਲਿਆ।"
     "%1$d / %2$d"
     "ਫ਼ਾਈਲ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"
diff --git a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
index f791b6d..7708adc 100644
--- a/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pl/strings.xml
@@ -47,6 +47,9 @@
     "strony od %1$d do %2$d%3$d"
     "Obraz: %1$s"
     "Znajdź w pliku"
+    "Wstecz"
+    "Dalej"
+    "Zamknij"
     "Brak wyników."
     "%1$d/%2$d"
     "Edytuj plik"
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
index 7e0ddc0..24daf9b 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rBR/strings.xml
@@ -47,6 +47,9 @@
     "páginas %1$d a %2$d de %3$d"
     "Imagem: %1$s"
     "Localizar no arquivo"
+    "Anterior"
+    "Próxima"
+    "Fechar"
     "Nenhum resultado encontrado."
     "%1$d / %2$d"
     "Editar arquivo"
diff --git a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
index 53c34e4..66510fb 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt-rPT/strings.xml
@@ -47,6 +47,9 @@
     "páginas %1$d a %2$d de %3$d"
     "Imagem: %1$s"
     "Procure no ficheiro"
+    "Anterior"
+    "Seguinte"
+    "Fechar"
     "Sem correspondências."
     "%1$d/%2$d"
     "Editar ficheiro"
diff --git a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
index 7e0ddc0..24daf9b 100644
--- a/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-pt/strings.xml
@@ -47,6 +47,9 @@
     "páginas %1$d a %2$d de %3$d"
     "Imagem: %1$s"
     "Localizar no arquivo"
+    "Anterior"
+    "Próxima"
+    "Fechar"
     "Nenhum resultado encontrado."
     "%1$d / %2$d"
     "Editar arquivo"
diff --git a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
index 06344cf..237d9d8 100644
--- a/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ro/strings.xml
@@ -47,6 +47,9 @@
     "paginile %1$d%2$d din %3$d"
     "Imagine: %1$s"
     "Găsește în fișier"
+    "Înapoi"
+    "Înainte"
+    "Închide"
     "Nicio potrivire găsită."
     "%1$d / %2$d"
     "Editează fișierul"
diff --git a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
index 7f1fe6b..8717ce9 100644
--- a/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ru/strings.xml
@@ -47,6 +47,9 @@
     "страницы %1$d%2$d из %3$d"
     "Изображение: %1$s"
     "Найти в файле"
+    "Назад"
+    "Далее"
+    "Закрыть"
     "Ничего не найдено."
     "%1$d из %2$d"
     "Редактировать файл"
diff --git a/pdf/pdf-viewer/src/main/res/values-si/strings.xml b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
index 54c42c3..51bb62b 100644
--- a/pdf/pdf-viewer/src/main/res/values-si/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-si/strings.xml
@@ -47,6 +47,9 @@
     "පිටු %3$dන් %1$d සිට %2$d දක්වා"
     "රූපය: %1$s"
     "ගොනුව සොයා ගන්න"
+    "පෙර"
+    "මීළඟ"
+    "වසන්න"
     "කිසි ගැළපීමක් හමු නොවිය."
     "%1$d / %2$d"
     "ගොනුව සංස්කරණ කරන්න"
diff --git a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
index f2886cd..33e0d7d 100644
--- a/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sk/strings.xml
@@ -47,6 +47,9 @@
     "strany od %1$d do %2$d%3$d"
     "Obrázok: %1$s"
     "Vyhľadajte v súbore"
+    "Naspäť"
+    "Ďalej"
+    "Zavrieť"
     "Neboli nájdené žiadne zhody."
     "%1$d / %2$d"
     "Upraviť súbor"
diff --git a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
index 457b9f1..b7b63b9 100644
--- a/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sl/strings.xml
@@ -47,6 +47,9 @@
     "strani %1$d do %2$d od %3$d"
     "Slika: %1$s"
     "Iskanje v datoteki"
+    "Nazaj"
+    "Naprej"
+    "Zapri"
     "Ni rezultatov."
     "%1$d/%2$d"
     "Urejanje datoteke"
diff --git a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
index ece0da4..36ec3d71 100644
--- a/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sq/strings.xml
@@ -47,6 +47,9 @@
     "faqet nga %1$d deri në %2$d nga %3$d"
     "Imazhi: %1$s"
     "Gjej te skedari"
+    "Pas"
+    "Para"
+    "Mbyll"
     "Nuk u gjetën përputhje."
     "%1$d / %2$d"
     "Modifiko skedarin"
diff --git a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
index e8b8b9c..8bc67cc4 100644
--- a/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sr/strings.xml
@@ -47,6 +47,9 @@
     "странице %1$d. до %2$d. од %3$d"
     "Слика: %1$s"
     "Пронађите у фајлу"
+    "Претходно"
+    "Даље"
+    "Затвори"
     "Није пронађено ниједно подударање."
     "%1$d/%2$d"
     "Измени фајл"
diff --git a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
index 90ee5c1..e4535818 100644
--- a/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sv/strings.xml
@@ -47,6 +47,9 @@
     "sidorna %1$d till %2$d av %3$d"
     "Bild: %1$s"
     "Hitta i filen"
+    "Föregående"
+    "Nästa"
+    "Stäng"
     "Inga matchningar hittades."
     "%1$d/%2$d"
     "Redigera fil"
diff --git a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
index 2219b10..3722f1b 100644
--- a/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-sw/strings.xml
@@ -47,6 +47,9 @@
     "ukurasa wa %1$d hadi %2$d kati ya %3$d"
     "Picha: %1$s"
     "Tafuta kwenye faili"
+    "Iliyotangulia"
+    "Endelea"
+    "Funga"
     "Hakuna vipengee vinavyolingana."
     "%1$d kati ya %2$d"
     "Badilisha faili"
diff --git a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
index 4c28feb..c30814a 100644
--- a/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ta/strings.xml
@@ -47,6 +47,9 @@
     "%3$d பக்கங்களில் %1$dமுதல் %2$d வரை"
     "படம்: %1$s"
     "ஃபைலில் தேடுக"
+    "முந்தையதற்குச் செல்லும்"
+    "அடுத்ததற்குச் செல்லும்"
+    "மூடும்"
     "பொருத்தங்கள் கண்டறியப்படவில்லை."
     "%1$d / %2$d"
     "ஃபைலைத் திருத்து"
diff --git a/pdf/pdf-viewer/src/main/res/values-te/strings.xml b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
index 26c2954..c1b36a4 100644
--- a/pdf/pdf-viewer/src/main/res/values-te/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-te/strings.xml
@@ -47,6 +47,9 @@
     "%3$dలో %1$d నుండి %2$d పేజీలు"
     "ఇమేజ్: %1$s"
     "ఫైల్‌లో కనుగొనండి"
+    "మునుపటి"
+    "తర్వాత"
+    "మూసివేయండి"
     "మ్యాచ్‌లు ఏవీ దొరకలేదు."
     "మొత్తం %2$dలో %1$d"
     "ఫైల్‌ను ఎడిట్ చేయండి"
diff --git a/pdf/pdf-viewer/src/main/res/values-th/strings.xml b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
index 4565375..a98e640 100644
--- a/pdf/pdf-viewer/src/main/res/values-th/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-th/strings.xml
@@ -47,6 +47,9 @@
     "หน้า %1$d ถึง %2$d จาก %3$d"
     "รูปภาพ: %1$s"
     "ค้นหาในไฟล์"
+    "ก่อนหน้า"
+    "ถัดไป"
+    "ปิด"
     "ไม่พบข้อมูลที่ตรงกัน"
     "%1$d/%2$d"
     "แก้ไขไฟล์"
diff --git a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
index 6399462..c3072d5 100644
--- a/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tl/strings.xml
@@ -47,6 +47,9 @@
     "page %1$d hanggang %2$d sa %3$d"
     "Larawan: %1$s"
     "Maghanap sa file"
+    "Nakaraan"
+    "Susunod"
+    "Isara"
     "Walang nahanap na tugma."
     "%1$d / %2$d"
     "I-edit ang file"
diff --git a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
index c306300..012357c 100644
--- a/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-tr/strings.xml
@@ -47,6 +47,9 @@
     "sayfa %1$d-%2$d/%3$d"
     "Resim: %1$s"
     "Dosyada bul"
+    "Önceki"
+    "Sonraki"
+    "Kapat"
     "Eşleşme bulunamadı."
     "%1$d/%2$d"
     "Dosyayı düzenle"
diff --git a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
index 8585b92..2142d29 100644
--- a/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uk/strings.xml
@@ -47,6 +47,9 @@
     "сторінки %1$d%2$d з %3$d"
     "Зображення: %1$s"
     "Пошук у файлі"
+    "Назад"
+    "Далі"
+    "Закрити"
     "Нічого не знайдено."
     "%1$d/%2$d"
     "Редагувати файл"
diff --git a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
index 10a6c0a..d419abd 100644
--- a/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-ur/strings.xml
@@ -47,6 +47,9 @@
     "صفحات %1$d سے %2$d از %3$d"
     "تصویر: %1$s"
     "فائل میں تلاش کریں"
+    "پچھلا"
+    "اگلا"
+    "بند کریں"
     "کسی مماثلت کا پتا نہیں چلا۔"
     "%2$d / %1$d"
     "فائل میں ترمیم کریں"
diff --git a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
index c313d09..07974d4 100644
--- a/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-uz/strings.xml
@@ -47,6 +47,9 @@
     "sahifalar: %1$d-%2$d / %3$d"
     "Tasvir: %1$s"
     "Fayl ichidan topish"
+    "Avvalgisi"
+    "Keyingisi"
+    "Yopish"
     "Hech narsa topilmadi."
     "%1$d / %2$d"
     "Faylni tahrirlash"
diff --git a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
index ea11021..ea77da0 100644
--- a/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-vi/strings.xml
@@ -47,6 +47,9 @@
     "các trang %1$d đến %2$d trong số %3$d"
     "Hình ảnh: %1$s"
     "Tìm trong tệp"
+    "Trước"
+    "Tiếp theo"
+    "Đóng"
     "Không tìm thấy kết quả phù hợp."
     "%1$d/%2$d"
     "Chỉnh sửa tệp"
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
index aea5179..4722e74 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rCN/strings.xml
@@ -47,6 +47,9 @@
     "第 %1$d-%2$d 页,共 %3$d 页"
     "图片:%1$s"
     "在文件中查找"
+    "上一页"
+    "下一页"
+    "关闭"
     "未找到匹配项。"
     "%1$d / %2$d"
     "编辑文件"
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
index 8cff251..9e03b59 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rHK/strings.xml
@@ -47,6 +47,9 @@
     "第 %1$d%2$d 頁 (共 %3$d 頁)"
     "圖片:%1$s"
     "在檔案中搜尋"
+    "上一個"
+    "下一個"
+    "閂"
     "找不到相符項目。"
     "%1$d/%2$d"
     "編輯檔案"
diff --git a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
index 57010b7..20fabae 100644
--- a/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zh-rTW/strings.xml
@@ -47,6 +47,9 @@
     "第 %1$d%2$d 頁,共 %3$d 頁"
     "圖片:%1$s"
     "在檔案中搜尋"
+    "上一個"
+    "下一個"
+    "關閉"
     "找不到相符項目。"
     "%1$d/%2$d"
     "編輯檔案"
diff --git a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
index 8d4f6b1..85e46fb 100644
--- a/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
+++ b/pdf/pdf-viewer/src/main/res/values-zu/strings.xml
@@ -47,6 +47,9 @@
     "amakhasi %1$d ukuya ku-%2$d kwangu-%3$d"
     "Umfanekiso: %1$s"
     "Thola kufayela"
+    "Okwangaphambilini"
+    "Okulandelayo"
+    "Vala"
     "Akukho okufanayo okutholiwe."
     "%1$d / %2$d"
     "Hlela ifayela"
diff --git a/playground-common/playground-plugin/build.gradle b/playground-common/playground-plugin/build.gradle
index c5b8bb8..8081016 100644
--- a/playground-common/playground-plugin/build.gradle
+++ b/playground-common/playground-plugin/build.gradle
@@ -21,7 +21,7 @@
 
 dependencies {
     implementation(project(":shared"))
-    implementation("com.gradle:develocity-gradle-plugin:3.17.2")
+    implementation("com.gradle:develocity-gradle-plugin:3.18")
     implementation("com.gradle:common-custom-user-data-gradle-plugin:2.0.1")
     implementation("supportBuildSrc:private")
     implementation("supportBuildSrc:public")
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index e3086fc..b7c215d 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -26,5 +26,5 @@
 # Disable docs
 androidx.enableDocumentation=false
 androidx.playground.snapshotBuildId=11349412
-androidx.playground.metalavaBuildId=12216051
-androidx.studio.type=playground
\ No newline at end of file
+androidx.playground.metalavaBuildId=12253410
+androidx.studio.type=playground
diff --git a/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParser.kt b/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParser.kt
index 1e0e45f..25f5c7b 100644
--- a/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParser.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParser.kt
@@ -59,6 +59,22 @@
         ) {
             logger.error("Error in $name: annotated interfaces cannot declare companion objects.")
         }
+        if (
+            interfaceDeclaration.declarations
+                .filterIsInstance()
+                .filter {
+                    listOf(
+                            ClassKind.OBJECT,
+                            ClassKind.INTERFACE,
+                            ClassKind.ENUM_CLASS,
+                            ClassKind.CLASS
+                        )
+                        .contains(it.classKind)
+                }
+                .any { !it.isCompanionObject }
+        ) {
+            logger.error("Error in $name: annotated interfaces cannot declare objects or classes.")
+        }
         val invalidModifiers =
             interfaceDeclaration.modifiers.filterNot(validInterfaceModifiers::contains)
         if (invalidModifiers.isNotEmpty()) {
diff --git a/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParser.kt b/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParser.kt
index 8811255..6f548dc 100644
--- a/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParser.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/main/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParser.kt
@@ -51,6 +51,7 @@
             logger.error("Error in $name: annotated values should be public.")
         }
         ensureNoCompanion(value, name)
+        ensureNoObject(value, name)
         ensureNoTypeParameters(value, name)
         ensureNoSuperTypes(value, name)
 
@@ -86,6 +87,25 @@
         }
     }
 
+    private fun ensureNoObject(classDeclaration: KSClassDeclaration, name: String) {
+        if (
+            classDeclaration.declarations
+                .filterIsInstance()
+                .filter {
+                    listOf(
+                            ClassKind.OBJECT,
+                            ClassKind.INTERFACE,
+                            ClassKind.ENUM_CLASS,
+                            ClassKind.CLASS
+                        )
+                        .contains(it.classKind)
+                }
+                .any { !it.isCompanionObject }
+        ) {
+            logger.error("Error in $name: annotated values cannot declare objects or classes.")
+        }
+    }
+
     private fun ensureNoTypeParameters(classDeclaration: KSClassDeclaration, name: String) {
         if (classDeclaration.typeParameters.isNotEmpty()) {
             logger.error(
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
index 9cb0abf..975ee9a 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
@@ -256,6 +256,71 @@
     }
 
     @Test
+    fun interfaceWithObject_fails() {
+        checkSourceFails(
+                serviceInterface(
+                    """public interface MySdk {
+                    |   object MyObject {
+                    |   }
+                    |}
+                """
+                        .trimMargin()
+                )
+            )
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdk: annotated interfaces cannot declare objects or classes."
+            )
+    }
+
+    @Test
+    fun interfaceWithEnumClass_fails() {
+        checkSourceFails(
+                serviceInterface(
+                    """public interface MySdk {
+                    |   enum class MyEnumClass {}
+                    |}
+                """
+                        .trimMargin()
+                )
+            )
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdk: annotated interfaces cannot declare objects or classes."
+            )
+    }
+
+    @Test
+    fun interfaceWithInterface_fails() {
+        checkSourceFails(
+                serviceInterface(
+                    """public interface MySdk {
+                    |   private interface MyInterface {}
+                    |}
+                """
+                        .trimMargin()
+                )
+            )
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdk: annotated interfaces cannot declare objects or classes."
+            )
+    }
+
+    @Test
+    fun interfaceWithInnerClass_fails() {
+        checkSourceFails(
+                serviceInterface(
+                    """public interface MySdk {
+                    |   class MyInnerClass {}
+                    |}
+                """
+                        .trimMargin()
+                )
+            )
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdk: annotated interfaces cannot declare objects or classes."
+            )
+    }
+
+    @Test
     fun interfaceWithInvalidModifier_fails() {
         checkSourceFails(
                 serviceInterface(
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParserTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParserTest.kt
index 3a486ea..88949a2 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParserTest.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/ValueParserTest.kt
@@ -218,6 +218,64 @@
     }
 
     @Test
+    fun dataClassWithObject_fails() {
+        val dataClass =
+            annotatedValue(
+                """
+            |data class MySdkRequest(val id: Int) {
+            |   object Constants {
+            |       val someConstant = 12
+            |   }
+            |}
+        """
+                    .trimMargin()
+            )
+        checkSourceFails(dataClass)
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdkRequest: annotated values cannot declare objects or " +
+                    "classes."
+            )
+    }
+
+    @Test
+    fun dataClassWithInnerClass_fails() {
+        val dataClass =
+            annotatedValue(
+                """
+            |data class MySdkRequest(val id: Int) {
+            |   class MyClass {
+            |       val someConstant = 12
+            |   }
+            |}
+        """
+                    .trimMargin()
+            )
+        checkSourceFails(dataClass)
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdkRequest: annotated values cannot declare objects or " +
+                    "classes."
+            )
+    }
+
+    @Test
+    fun dataClassWithEnumClass_fails() {
+        val dataClass =
+            annotatedValue(
+                """
+            |data class MySdkRequest(val id: Int) {
+            |   enum class MyClass { RED, GREEN }
+            |}
+        """
+                    .trimMargin()
+            )
+        checkSourceFails(dataClass)
+            .containsExactlyErrors(
+                "Error in com.mysdk.MySdkRequest: annotated values cannot declare objects or " +
+                    "classes."
+            )
+    }
+
+    @Test
     fun dataClassWithTypeParameters_fails() {
         val dataClass = annotatedValue("data class MySdkRequest(val id: Int, val data: T)")
         checkSourceFails(dataClass)
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/build.gradle b/privacysandbox/ui/integration-tests/sdkproviderutils/build.gradle
index 2a9b90d9c..323d9a0 100644
--- a/privacysandbox/ui/integration-tests/sdkproviderutils/build.gradle
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/build.gradle
@@ -29,4 +29,7 @@
     implementation project(':privacysandbox:ui:ui-provider')
     implementation project(':privacysandbox:ui:integration-tests:testaidl')
     implementation project(':webkit:webkit')
+    implementation(libs.media3Ui)
+    implementation(libs.media3Common)
+    implementation(libs.media3Exoplayer)
 }
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/MediateeSdkApiImpl.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/MediateeSdkApiImpl.kt
index e647c7a..4cf8dab 100644
--- a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/MediateeSdkApiImpl.kt
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/MediateeSdkApiImpl.kt
@@ -42,6 +42,7 @@
             when (adType) {
                 AdType.WEBVIEW -> loadWebViewBannerAd()
                 AdType.WEBVIEW_FROM_LOCAL_ASSETS -> loadWebViewBannerAdFromLocalAssets()
+                AdType.NON_WEBVIEW_VIDEO -> loadVideoAd()
                 else -> loadNonWebViewBannerAd(mediationDescription, waitInsideOnDraw)
             }
         ViewabilityHandler.addObserverFactoryToAdapter(adapter, drawViewability)
@@ -56,6 +57,13 @@
         return testAdapters.WebViewAdFromLocalAssets()
     }
 
+    private fun loadVideoAd(): SandboxedUiAdapter {
+        val playerViewProvider = PlayerViewProvider()
+        val adapter = testAdapters.VideoBannerAd(playerViewProvider)
+        PlayerViewabilityHandler.addObserverFactoryToAdapter(adapter, playerViewProvider)
+        return adapter
+    }
+
     private fun loadNonWebViewBannerAd(
         text: String,
         waitInsideOnDraw: Boolean
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewProvider.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewProvider.kt
new file mode 100644
index 0000000..efa13eb
--- /dev/null
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewProvider.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ui.integration.sdkproviderutils
+
+import android.content.Context
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import androidx.media3.common.AudioAttributes
+import androidx.media3.common.C
+import androidx.media3.common.MediaItem
+import androidx.media3.common.Player
+import androidx.media3.exoplayer.ExoPlayer
+import androidx.media3.ui.PlayerView
+import java.util.WeakHashMap
+
+/** Create PlayerView with Player and controlling playback based on player visibility. */
+class PlayerViewProvider {
+
+    private val handler = Handler(Looper.getMainLooper())
+    private val createdViews = WeakHashMap()
+
+    fun createPlayerView(windowContext: Context, videoUrl: String): View {
+        val viewId = View.generateViewId()
+
+        val view = PlayerView(windowContext)
+        view.id = viewId
+
+        val playerWithState = PlayerWithState(windowContext, videoUrl)
+        createdViews[view] = playerWithState
+
+        return view
+    }
+
+    fun onPlayerVisible(id: Int) {
+        Log.i(TAG, "onPlayerVisible: $id")
+        handler.post {
+            for ((view: PlayerView, state: PlayerWithState) in createdViews) {
+                if (view.player == null) {
+                    val player = state.initializePlayer()
+                    view.setPlayer(player)
+                }
+                if (view.id == id && view.player?.isPlaying == false) {
+                    Log.i(TAG, "onPlayerVisible: resuming $id")
+                    view.player?.play()
+                }
+            }
+        }
+    }
+
+    fun onPlayerInvisible(id: Int) {
+        Log.i(TAG, "onPlayerInVisible: $id")
+        handler.post {
+            for ((view: PlayerView, _: PlayerWithState) in createdViews) {
+                if (view.id == id) {
+                    Log.i(TAG, "onPlayerInVisible: pausing $id")
+                    view.player?.pause()
+                }
+            }
+        }
+    }
+
+    fun onSessionClosed() {
+        Log.i(TAG, "onSessionClosed, releasing player resources")
+        handler.post {
+            for ((view: PlayerView, state: PlayerWithState) in createdViews) {
+                state.releasePlayer()
+                view.setPlayer(null)
+            }
+        }
+        createdViews.clear()
+    }
+
+    inner class PlayerWithState(private val context: Context, private val videoUrl: String) {
+        private var player: ExoPlayer? = null
+        private var autoPlay = true
+        private var autoPlayPosition: Long
+
+        init {
+            autoPlayPosition = C.TIME_UNSET
+        }
+
+        fun initializePlayer(): Player? {
+            player?.let {
+                return it
+            }
+
+            val audioAttributes =
+                AudioAttributes.Builder()
+                    .setUsage(C.USAGE_MEDIA)
+                    .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE)
+                    .build()
+
+            player = ExoPlayer.Builder(context).setAudioAttributes(audioAttributes, true).build()
+            player?.apply {
+                setPlayWhenReady(autoPlay)
+                setMediaItem(MediaItem.fromUri(Uri.parse(videoUrl)))
+                val hasStartPosition = autoPlayPosition != C.TIME_UNSET
+                if (hasStartPosition) {
+                    seekTo(0, autoPlayPosition)
+                }
+                prepare()
+            }
+
+            return player
+        }
+
+        fun releasePlayer() {
+            player?.run {
+                autoPlay = playWhenReady
+                autoPlayPosition = contentPosition
+                release()
+            }
+            player = null
+        }
+    }
+
+    private companion object {
+        const val TAG = "PlayerViewProvider"
+    }
+}
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewabilityHandler.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewabilityHandler.kt
new file mode 100644
index 0000000..25a3851
--- /dev/null
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/PlayerViewabilityHandler.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ui.integration.sdkproviderutils
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.privacysandbox.ui.core.SandboxedSdkViewUiInfo
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SessionObserver
+import androidx.privacysandbox.ui.core.SessionObserverContext
+import androidx.privacysandbox.ui.core.SessionObserverFactory
+
+class PlayerViewabilityHandler {
+
+    private class SessionObserverFactoryImpl(val playerViewProvider: PlayerViewProvider) :
+        SessionObserverFactory {
+
+        override fun create(): SessionObserver {
+            return SessionObserverImpl(playerViewProvider)
+        }
+
+        private inner class SessionObserverImpl(val playerViewProvider: PlayerViewProvider) :
+            SessionObserver {
+            lateinit var view: View
+            var isPlayerVisible = false
+
+            override fun onSessionOpened(sessionObserverContext: SessionObserverContext) {
+                Log.i(TAG, "onSessionOpened $sessionObserverContext")
+                view = checkNotNull(sessionObserverContext.view)
+            }
+
+            override fun onUiContainerChanged(uiContainerInfo: Bundle) {
+                val sandboxedSdkViewUiInfo = SandboxedSdkViewUiInfo.fromBundle(uiContainerInfo)
+                Log.i(TAG, "onUiContainerChanged $sandboxedSdkViewUiInfo")
+
+                val updatedVisibility = !sandboxedSdkViewUiInfo.onScreenGeometry.isEmpty
+                if (updatedVisibility != isPlayerVisible) {
+                    Log.i(
+                        TAG,
+                        "Video player previous visibility $isPlayerVisible, updated visibility $updatedVisibility"
+                    )
+                    isPlayerVisible = updatedVisibility
+                    if (isPlayerVisible) {
+                        playerViewProvider.onPlayerVisible(view.id)
+                    } else {
+                        playerViewProvider.onPlayerInvisible(view.id)
+                    }
+                }
+            }
+
+            override fun onSessionClosed() {
+                Log.i(TAG, "session closed")
+                playerViewProvider.onSessionClosed()
+            }
+        }
+    }
+
+    companion object {
+
+        private val TAG = PlayerViewabilityHandler::class.simpleName
+
+        fun addObserverFactoryToAdapter(
+            adapter: SandboxedUiAdapter,
+            playerViewProvider: PlayerViewProvider
+        ) {
+            return adapter.addObserverFactory(SessionObserverFactoryImpl(playerViewProvider))
+        }
+    }
+}
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/SdkApiConstants.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/SdkApiConstants.kt
index 19b8b01..f299659 100644
--- a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/SdkApiConstants.kt
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/SdkApiConstants.kt
@@ -24,6 +24,7 @@
                 const val NON_WEBVIEW = 0
                 const val WEBVIEW = 1
                 const val WEBVIEW_FROM_LOCAL_ASSETS = 2
+                const val NON_WEBVIEW_VIDEO = 3
             }
         }
 
diff --git a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
index 7c41a22..b613689 100644
--- a/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
+++ b/privacysandbox/ui/integration-tests/sdkproviderutils/src/main/java/androidx/privacysandbox/ui/integration/sdkproviderutils/TestAdapters.kt
@@ -126,6 +126,16 @@
         }
     }
 
+    inner class VideoBannerAd(private val playerViewProvider: PlayerViewProvider) : BannerAd() {
+
+        override fun buildAdView(sessionContext: Context): View {
+            return playerViewProvider.createPlayerView(
+                sessionContext,
+                "https://html5demos.com/assets/dizzy.mp4"
+            )
+        }
+    }
+
     inner class WebViewAdFromLocalAssets : BannerAd() {
         override fun buildAdView(sessionContext: Context): View {
             val webView = WebView(sessionContext)
diff --git a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
index a54d6f1..91609907 100644
--- a/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/java/androidx/privacysandbox/ui/integration/testapp/MainActivity.kt
@@ -49,12 +49,13 @@
     private lateinit var navigationView: NavigationView
     private lateinit var currentFragment: BaseFragment
     private lateinit var triggerSandboxDeathButton: Button
-    private lateinit var webViewToggleButton: SwitchMaterial
     private lateinit var zOrderToggleButton: SwitchMaterial
-    private lateinit var contentFromAssetsToggleButton: SwitchMaterial
     private lateinit var viewabilityToggleButton: SwitchMaterial
     private lateinit var mediationDropDownMenu: Spinner
+    private lateinit var adTypeDropDownMenu: Spinner
+
     @AdType private var adType = AdType.NON_WEBVIEW
+
     @MediationOption private var mediationOption = MediationOption.NON_MEDIATED
     private var drawViewabilityLayer = false
 
@@ -65,12 +66,11 @@
         setContentView(R.layout.activity_main)
         drawerLayout = findViewById(R.id.drawer)
         navigationView = findViewById(R.id.navigation_view)
-        contentFromAssetsToggleButton = findViewById(R.id.content_from_assets_switch)
         zOrderToggleButton = findViewById(R.id.zorder_below_switch)
-        webViewToggleButton = findViewById(R.id.load_webview)
         viewabilityToggleButton = findViewById(R.id.display_viewability_switch)
         triggerSandboxDeathButton = findViewById(R.id.trigger_sandbox_death)
         mediationDropDownMenu = findViewById(R.id.mediation_dropdown_menu)
+        adTypeDropDownMenu = findViewById(R.id.ad_type_dropdown_menu)
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
             // there is no sandbox to kill on T-
@@ -139,59 +139,26 @@
     }
 
     private fun initializeToggles() {
-        initializeWebViewToggleSwitch()
-        initializeContentFromAssetsToggleButton()
         initializeViewabilityToggleButton()
         initializeMediationDropDown()
+        initializeAdTypeDropDown()
         initializeZOrderToggleButton()
     }
 
     private fun disableAllControls() {
-        webViewToggleButton.isEnabled = false
-        contentFromAssetsToggleButton.isEnabled = false
         mediationDropDownMenu.isEnabled = false
+        adTypeDropDownMenu.isEnabled = false
         viewabilityToggleButton.isEnabled = false
         zOrderToggleButton.isEnabled = false
     }
 
     private fun enableAllControls() {
-        webViewToggleButton.isEnabled = true
-        contentFromAssetsToggleButton.isEnabled = webViewToggleButton.isChecked
         mediationDropDownMenu.isEnabled = true
+        adTypeDropDownMenu.isEnabled = true
         viewabilityToggleButton.isEnabled = true
         zOrderToggleButton.isEnabled = true
     }
 
-    private fun initializeWebViewToggleSwitch() {
-        contentFromAssetsToggleButton.isEnabled = false
-        webViewToggleButton.setOnCheckedChangeListener { _, isChecked ->
-            contentFromAssetsToggleButton.isEnabled = isChecked
-            adType =
-                if (isChecked) {
-                    if (contentFromAssetsToggleButton.isChecked) {
-                        AdType.WEBVIEW_FROM_LOCAL_ASSETS
-                    } else {
-                        AdType.WEBVIEW
-                    }
-                } else {
-                    AdType.NON_WEBVIEW
-                }
-            loadAllAds()
-        }
-    }
-
-    private fun initializeContentFromAssetsToggleButton() {
-        contentFromAssetsToggleButton.setOnCheckedChangeListener { _, isChecked ->
-            adType =
-                if (isChecked) {
-                    AdType.WEBVIEW_FROM_LOCAL_ASSETS
-                } else {
-                    AdType.WEBVIEW
-                }
-            loadAllAds()
-        }
-    }
-
     private fun initializeViewabilityToggleButton() {
         viewabilityToggleButton.setOnCheckedChangeListener { _, isChecked ->
             drawViewabilityLayer = isChecked
@@ -252,6 +219,46 @@
             }
     }
 
+    private fun initializeAdTypeDropDown() {
+        ArrayAdapter.createFromResource(
+                applicationContext,
+                R.array.ad_type_dropdown_menu_array,
+                android.R.layout.simple_spinner_item
+            )
+            .also { adapter ->
+                adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+                adTypeDropDownMenu.adapter = adapter
+            }
+
+        adTypeDropDownMenu.onItemSelectedListener =
+            object : AdapterView.OnItemSelectedListener {
+                var isCalledOnStartingApp = true
+
+                override fun onItemSelected(
+                    parent: AdapterView<*>?,
+                    view: View?,
+                    position: Int,
+                    selectedAdOptionId: Long
+                ) {
+                    if (isCalledOnStartingApp) {
+                        isCalledOnStartingApp = false
+                        return
+                    }
+                    adType =
+                        when (position) {
+                            0 -> AdType.NON_WEBVIEW
+                            1 -> AdType.WEBVIEW
+                            2 -> AdType.WEBVIEW_FROM_LOCAL_ASSETS
+                            3 -> AdType.NON_WEBVIEW_VIDEO
+                            else -> AdType.NON_WEBVIEW
+                        }
+                    loadAllAds()
+                }
+
+                override fun onNothingSelected(parent: AdapterView<*>?) {}
+            }
+    }
+
     private fun initializeZOrderToggleButton() {
         zOrderToggleButton.setOnCheckedChangeListener { _, isChecked ->
             BaseFragment.isZOrderOnTop = !isChecked
@@ -264,7 +271,6 @@
             if (drawerLayout.isOpen) {
                 drawerLayout.closeDrawers()
             } else {
-                currentFragment.handleDrawerStateChange(true)
                 drawerLayout.open()
             }
         }
@@ -273,14 +279,20 @@
     private fun initializeDrawer() {
         drawerLayout.addDrawerListener(
             object : DrawerListener {
-                override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
+                private var isDrawerOpen = false
 
-                override fun onDrawerOpened(drawerView: View) {
-                    // we handle this in the button onClick instead
+                override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
+                    if (!isDrawerOpen) {
+                        isDrawerOpen = true
+                        currentFragment.handleDrawerStateChange(isDrawerOpen = true)
+                    }
                 }
 
+                override fun onDrawerOpened(drawerView: View) {}
+
                 override fun onDrawerClosed(drawerView: View) {
-                    currentFragment.handleDrawerStateChange(false)
+                    isDrawerOpen = false
+                    currentFragment.handleDrawerStateChange(isDrawerOpen = false)
                 }
 
                 override fun onDrawerStateChanged(newState: Int) {}
diff --git a/privacysandbox/ui/integration-tests/testapp/src/main/res/layout/activity_main.xml b/privacysandbox/ui/integration-tests/testapp/src/main/res/layout/activity_main.xml
index 0779727..6b72533 100644
--- a/privacysandbox/ui/integration-tests/testapp/src/main/res/layout/activity_main.xml
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/res/layout/activity_main.xml
@@ -16,33 +16,38 @@
   -->
 
 
-    xmlns:tools="http://schemas.android.com/tools"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/drawer"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context=".MainActivity">
+
     
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical">
+
         
+            android:id="@+id/toggle_drawer_button"
             android:layout_width="match_parent"
             android:layout_height="50dp"
-            android:id="@+id/toggle_drawer_button"
-            android:text="Open Options"/>
+            android:text="Open Options" />
+
         
             android:id="@+id/content_fragment_container"
             android:layout_width="match_parent"
             android:layout_height="0dp"
-            android:layout_weight="1"/>
+            android:layout_weight="1" />
     
+
     
         android:id="@+id/navigation_view"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:layout_gravity="start"
         app:menu="@layout/action_menu">
+
         
             android:id="@+id/mediation_dropdown_menu"
             android:layout_width="match_parent"
@@ -50,44 +55,40 @@
             android:layout_gravity="center"
             android:background="@android:drawable/btn_dropdown"
             android:spinnerMode="dropdown" />
-        
-            android:id="@+id/load_webview"
-            android:layout_width="wrap_content"
+
+        
+            android:id="@+id/ad_type_dropdown_menu"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_gravity="center"
             android:layout_marginTop="50dp"
-            android:layout_gravity="center"
-            android:text="@string/webview_switch"
-            android:checked="false" />
-        
-            android:id="@+id/content_from_assets_switch"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="100dp"
-            android:layout_gravity="center"
-            android:text="@string/content_from_assets_switch"
-            android:checked="false" />
+            android:background="@android:drawable/btn_dropdown"
+            android:spinnerMode="dropdown" />
+
         
             android:id="@+id/display_viewability_switch"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="150dp"
             android:layout_gravity="center"
-            android:text="@string/display_viewability_switch"
-            android:checked="false"/>
+            android:layout_marginTop="100dp"
+            android:checked="false"
+            android:text="@string/display_viewability_switch" />
+
         
             android:id="@+id/zorder_below_switch"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="200dp"
             android:layout_gravity="center"
-            android:text="@string/zorder_below_switch"
-            android:checked="false" />
+            android:layout_marginTop="150dp"
+            android:checked="false"
+            android:text="@string/zorder_below_switch" />
+
         
+            android:id="@+id/trigger_sandbox_death"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="250dp"
             android:layout_gravity="center"
-            android:id="@+id/trigger_sandbox_death"
-            android:text="@string/trigger_sandbox_death_button"/>
+            android:layout_marginTop="200dp"
+            android:text="@string/trigger_sandbox_death_button" />
     
 
diff --git a/tv/integration-tests/presentation/src/main/res/values/themes.xml b/privacysandbox/ui/integration-tests/testapp/src/main/res/values/ad_type_options.xml
similarity index 61%
rename from tv/integration-tests/presentation/src/main/res/values/themes.xml
rename to privacysandbox/ui/integration-tests/testapp/src/main/res/values/ad_type_options.xml
index 8df2c77..053a9a4 100644
--- a/tv/integration-tests/presentation/src/main/res/values/themes.xml
+++ b/privacysandbox/ui/integration-tests/testapp/src/main/res/values/ad_type_options.xml
@@ -1,5 +1,5 @@
-
 
 
-