Merge "Snap for 10285742 from 25f3d0e1e39f866fd1cf7af494c150fd8f281afe to androidx-health-release" into androidx-health-release
diff --git a/.github/actions/build-single-project/action.yml b/.github/actions/build-single-project/action.yml
index 79a8af1..b58866b 100644
--- a/.github/actions/build-single-project/action.yml
+++ b/.github/actions/build-single-project/action.yml
@@ -40,7 +40,7 @@
       run: echo "yes" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "cmake;3.22.1"
     - name: "Install Android SDK Build-Tools"
       shell: bash
-      run: echo "yes" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "build-tools;34.0.0-rc4"
+      run: echo "yes" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --install "build-tools;34.0.0"
     - name: "Set environment variables"
       shell: bash
       run: |
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/ValueUtils.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/ValueUtils.kt
new file mode 100644
index 0000000..14611c9
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/ValueUtils.kt
@@ -0,0 +1,121 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers
+
+import androidx.appactions.interaction.protobuf.ListValue
+import androidx.appactions.interaction.protobuf.Struct
+import androidx.appactions.interaction.protobuf.Value
+
+fun stringValue(string: String): Value {
+  return Value.newBuilder().setStringValue(string).build()
+}
+
+fun numberValue(number: Double): Value {
+  return Value.newBuilder().setNumberValue(number).build()
+}
+
+fun boolValue(bool: Boolean): Value {
+  return Value.newBuilder().setBoolValue(bool).build()
+}
+
+fun structValue(jsonObj: Struct): Value {
+  return Value.newBuilder().setStructValue(jsonObj).build()
+}
+
+fun listValue(elements: Iterable<Value>): Value {
+  return Value.newBuilder()
+      .setListValue(ListValue.newBuilder().addAllValues(elements).build())
+      .build()
+}
+
+/**
+ * Returns the string value if the [Value] holds a string or the first element in the list if
+ * the [Value] holds a list with a single string element.
+ *
+ * ```
+ * "Hello" -> "Hello"
+ * ["Hello"] -> "Hello"
+ * ["Hello", "World"] -> null
+ * {...} -> null
+ * ```
+ *
+ * This behavior can provide a bit of extra forward-compat where the JSON value originated from
+ * a newer process where it has been promoted to be repeated.
+ */
+val Value.singleStringValue: String?
+  get() {
+    return when {
+      hasStringValue() -> stringValue
+      hasListValue() ->
+          listValue.valuesList.onlyElementOrNull
+              ?.let { if (it.hasStringValue()) it.stringValue else null }
+      else -> null
+    }
+  }
+
+/**
+ * Returns the number value if the [Value] holds a number or the first element in the list if
+ * the [Value] holds a list with a single number element.
+ *
+ * ```
+ * 123 -> 123
+ * [123] -> 123
+ * [123, 456] -> null
+ * {...} -> null
+ * ```
+ *
+ * This behavior can provide a bit of extra forward-compat where the JSON value originated from
+ * a newer process where it has been promoted to be repeated.
+ */
+val Value.singleNumberValue: Double?
+    get() {
+        return when {
+            hasNumberValue() -> numberValue
+            hasListValue() ->
+                listValue.valuesList.onlyElementOrNull
+                    ?.let { if (it.hasNumberValue()) it.numberValue else null }
+            else -> null
+        }
+    }
+
+/**
+ * Returns the bool value if the [Value] holds a bool or the first element in the list if
+ * the [Value] holds a list with a single bool element.
+ *
+ * ```
+ * true -> true
+ * [true] -> true
+ * [true, false] -> null
+ * {...} -> null
+ * ```
+ *
+ * This behavior can provide a bit of extra forward-compat where the JSON value originated from
+ * a newer process where it has been promoted to be repeated.
+ */
+val Value.singleBoolValue: Boolean?
+    get() {
+        return when {
+            hasBoolValue() -> boolValue
+            hasListValue() ->
+                listValue.valuesList.onlyElementOrNull
+                    ?.let { if (it.hasBoolValue()) it.boolValue else null }
+            else -> null
+        }
+    }
+
+private val <T> List<T>.onlyElementOrNull: T?
+    get() = if (size == 1) first() else null
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializer.kt
similarity index 99%
rename from appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt
rename to appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializer.kt
index 7c783f8..9a15d65 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/BuiltInTypeSerializer.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializer.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.appactions.interaction.capabilities.serializers
+package androidx.appactions.interaction.capabilities.serializers.types
 
 import androidx.appactions.builtintypes.types.Thing
 import androidx.appactions.interaction.protobuf.Struct
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/Serialize.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/Serialize.kt
new file mode 100644
index 0000000..6a3ecb0
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/Serialize.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.Thing
+import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException
+import androidx.appactions.interaction.protobuf.Struct
+
+/**
+ * Converts the specified [Thing] (or subtype) to a JSON-LD conforming [Struct].
+ *
+ * Takes care of dynamically invoking the correct serializer based on the runtime type of the
+ * [instance]. For example,
+ * ```kt
+ * val person =
+ *   Person.Builder()
+ *     .setName("Jane")
+ *     .setEmail("jane@gmail.com")
+ *     .build()
+ * // {
+ * //   "@type": "Person",
+ * //   "name": "Jane",
+ * //   "email": "jane@gmail.com"
+ * // }
+ * val struct = serialize(person)
+ * ```
+ *
+ * @throws StructConversionException if some internal error occurs during serialization.
+ */
+fun serialize(@Suppress("UNUSED_PARAMETER") instance: Thing): Struct = TODO()
+
+/**
+ * Converts a JSON-LD conforming [Struct] to a [Thing] (or subtype).
+ *
+ * Takes care of dynamically invoking the correct serializer based on the "@type" field in the
+ * [struct]. For example,
+ * ```kt
+ * // {
+ * //   "@type": "Person",
+ * //   "name": "Jane",
+ * //   "email": "jane@gmail.com"
+ * // }
+ * val struct: Struct
+ * val thing = deserialize(struct)
+ *
+ * print(thing.name) // Jane
+ * if (thing is Person) {
+ *   println(thing.email) // jane@gmail.com
+ * }
+ * ```
+ *
+ * @throws StructConversionException If the [struct] refers to some unknown type.
+ */
+fun deserialize(@Suppress("UNUSED_PARAMETER") struct: Struct): Thing = TODO()
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/ValueUtilsTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/ValueUtilsTest.kt
new file mode 100644
index 0000000..7900c30
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/ValueUtilsTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers
+
+import androidx.appactions.interaction.protobuf.Struct
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ValueUtilsTest {
+  @Test
+  fun getSingleStringValue() {
+    assertThat(stringValue("Hello").singleStringValue).isEqualTo("Hello")
+    assertThat(listValue(listOf(stringValue("Hello"))).singleStringValue).isEqualTo("Hello")
+    assertThat(
+            listValue(
+                    listOf(
+                        stringValue("Hello"),
+                        stringValue("World"),
+                    ))
+                .singleStringValue)
+        .isNull()
+    assertThat(structValue(Struct.getDefaultInstance()).singleStringValue).isNull()
+  }
+
+  @Test
+  fun getSingleNumberValue() {
+      assertThat(numberValue(123.0).singleNumberValue).isEqualTo(123.0)
+      assertThat(listValue(listOf(numberValue(123.0))).singleNumberValue).isEqualTo(123.0)
+      assertThat(
+              listValue(
+                      listOf(
+                          numberValue(123.0),
+                          numberValue(456.0),
+                      ))
+                  .singleNumberValue)
+          .isNull()
+      assertThat(structValue(Struct.getDefaultInstance()).singleNumberValue).isNull()
+  }
+
+  @Test fun getSingleBoolValue() {
+      assertThat(boolValue(true).singleBoolValue).isTrue()
+      assertThat(listValue(listOf(boolValue(true))).singleBoolValue).isTrue()
+      assertThat(
+          listValue(
+              listOf(
+                  boolValue(true),
+                  boolValue(false),
+              ))
+              .singleBoolValue)
+          .isNull()
+      assertThat(structValue(Struct.getDefaultInstance()).singleBoolValue).isNull()
+  }
+}
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/SerializeTest.kt b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/SerializeTest.kt
new file mode 100644
index 0000000..c58103a
--- /dev/null
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/serializers/types/SerializeTest.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.appactions.interaction.capabilities.serializers.types
+
+import androidx.appactions.builtintypes.types.Person
+import androidx.appactions.interaction.capabilities.serializers.stringValue
+import androidx.appactions.interaction.protobuf.Struct
+import org.junit.Assert.assertThrows
+import org.junit.Test
+
+class SerializeTest {
+    @Test
+    fun serialize_ThrowsNotImplementedError() {
+        val person = Person.Builder().setName("Jane").setEmail("jane@gmail.com").build()
+        assertThrows(NotImplementedError::class.java) { serialize(person) }
+    }
+
+    @Test
+    fun deserialize_ThrowsNotImplementedError() {
+        val struct = Struct.newBuilder()
+            .putFields("@type", stringValue("Person"))
+            .putFields("name", stringValue("Jane"))
+            .putFields("email", stringValue("jane@gmail.com"))
+            .build()
+        assertThrows(NotImplementedError::class.java) { deserialize(struct) }
+    }
+}
diff --git a/appcompat/appcompat-resources/api/0.0.0.txt b/appcompat/appcompat-resources/api/0.0.0.txt
deleted file mode 100644
index 3b82dbb..0000000
--- a/appcompat/appcompat-resources/api/0.0.0.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-// Signature format: 2.0
-package androidx.appcompat.graphics.drawable {
-
-  public class AnimatedStateListDrawableCompat extends android.graphics.drawable.Drawable implements androidx.core.graphics.drawable.TintAwareDrawable {
-    ctor public AnimatedStateListDrawableCompat();
-    method public void addState(int[], android.graphics.drawable.Drawable, int);
-    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
-    method public static androidx.appcompat.graphics.drawable.AnimatedStateListDrawableCompat? create(android.content.Context, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.appcompat.graphics.drawable.AnimatedStateListDrawableCompat! createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void inflate(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-  }
-
-}
-
diff --git a/appcompat/appcompat/api/0.0.0.txt b/appcompat/appcompat/api/0.0.0.txt
deleted file mode 100644
index ba9551e..0000000
--- a/appcompat/appcompat/api/0.0.0.txt
+++ /dev/null
@@ -1,945 +0,0 @@
-package androidx.appcompat.app {
-
-  public abstract class ActionBar {
-    ctor public ActionBar();
-    method public abstract void addOnMenuVisibilityListener(androidx.appcompat.app.ActionBar.OnMenuVisibilityListener);
-    method public abstract deprecated void addTab(androidx.appcompat.app.ActionBar.Tab);
-    method public abstract deprecated void addTab(androidx.appcompat.app.ActionBar.Tab, boolean);
-    method public abstract deprecated void addTab(androidx.appcompat.app.ActionBar.Tab, int);
-    method public abstract deprecated void addTab(androidx.appcompat.app.ActionBar.Tab, int, boolean);
-    method public abstract android.view.View getCustomView();
-    method public abstract int getDisplayOptions();
-    method public float getElevation();
-    method public abstract int getHeight();
-    method public int getHideOffset();
-    method public abstract deprecated int getNavigationItemCount();
-    method public abstract deprecated int getNavigationMode();
-    method public abstract deprecated int getSelectedNavigationIndex();
-    method public abstract deprecated androidx.appcompat.app.ActionBar.Tab getSelectedTab();
-    method public abstract java.lang.CharSequence getSubtitle();
-    method public abstract deprecated androidx.appcompat.app.ActionBar.Tab getTabAt(int);
-    method public abstract deprecated int getTabCount();
-    method public android.content.Context getThemedContext();
-    method public abstract java.lang.CharSequence getTitle();
-    method public abstract void hide();
-    method public boolean isHideOnContentScrollEnabled();
-    method public abstract boolean isShowing();
-    method public abstract deprecated androidx.appcompat.app.ActionBar.Tab newTab();
-    method public abstract deprecated void removeAllTabs();
-    method public abstract void removeOnMenuVisibilityListener(androidx.appcompat.app.ActionBar.OnMenuVisibilityListener);
-    method public abstract deprecated void removeTab(androidx.appcompat.app.ActionBar.Tab);
-    method public abstract deprecated void removeTabAt(int);
-    method public abstract deprecated void selectTab(androidx.appcompat.app.ActionBar.Tab);
-    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public abstract void setCustomView(android.view.View);
-    method public abstract void setCustomView(android.view.View, androidx.appcompat.app.ActionBar.LayoutParams);
-    method public abstract void setCustomView(int);
-    method public abstract void setDisplayHomeAsUpEnabled(boolean);
-    method public abstract void setDisplayOptions(int);
-    method public abstract void setDisplayOptions(int, int);
-    method public abstract void setDisplayShowCustomEnabled(boolean);
-    method public abstract void setDisplayShowHomeEnabled(boolean);
-    method public abstract void setDisplayShowTitleEnabled(boolean);
-    method public abstract void setDisplayUseLogoEnabled(boolean);
-    method public void setElevation(float);
-    method public void setHideOffset(int);
-    method public void setHideOnContentScrollEnabled(boolean);
-    method public void setHomeActionContentDescription(java.lang.CharSequence);
-    method public void setHomeActionContentDescription(int);
-    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
-    method public void setHomeAsUpIndicator(int);
-    method public void setHomeButtonEnabled(boolean);
-    method public abstract void setIcon(int);
-    method public abstract void setIcon(android.graphics.drawable.Drawable);
-    method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, androidx.appcompat.app.ActionBar.OnNavigationListener);
-    method public abstract void setLogo(int);
-    method public abstract void setLogo(android.graphics.drawable.Drawable);
-    method public abstract deprecated void setNavigationMode(int);
-    method public abstract deprecated void setSelectedNavigationItem(int);
-    method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public abstract void setSubtitle(java.lang.CharSequence);
-    method public abstract void setSubtitle(int);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void setTitle(int);
-    method public abstract void show();
-    field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
-    field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
-    field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
-    field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
-    field public static final int DISPLAY_USE_LOGO = 1; // 0x1
-    field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
-    field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
-    field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
-  }
-
-  public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public ActionBar.LayoutParams(int, int);
-    ctor public ActionBar.LayoutParams(int, int, int);
-    ctor public ActionBar.LayoutParams(int);
-    ctor public ActionBar.LayoutParams(androidx.appcompat.app.ActionBar.LayoutParams);
-    ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
-    field public int gravity;
-  }
-
-  public static abstract interface ActionBar.OnMenuVisibilityListener {
-    method public abstract void onMenuVisibilityChanged(boolean);
-  }
-
-  public static abstract deprecated interface ActionBar.OnNavigationListener {
-    method public abstract boolean onNavigationItemSelected(int, long);
-  }
-
-  public static abstract deprecated class ActionBar.Tab {
-    ctor public ActionBar.Tab();
-    method public abstract java.lang.CharSequence getContentDescription();
-    method public abstract android.view.View getCustomView();
-    method public abstract android.graphics.drawable.Drawable getIcon();
-    method public abstract int getPosition();
-    method public abstract java.lang.Object getTag();
-    method public abstract java.lang.CharSequence getText();
-    method public abstract void select();
-    method public abstract androidx.appcompat.app.ActionBar.Tab setContentDescription(int);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setCustomView(android.view.View);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setCustomView(int);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setIcon(int);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setTabListener(androidx.appcompat.app.ActionBar.TabListener);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setTag(java.lang.Object);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setText(java.lang.CharSequence);
-    method public abstract androidx.appcompat.app.ActionBar.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static abstract deprecated interface ActionBar.TabListener {
-    method public abstract void onTabReselected(androidx.appcompat.app.ActionBar.Tab, androidx.fragment.app.FragmentTransaction);
-    method public abstract void onTabSelected(androidx.appcompat.app.ActionBar.Tab, androidx.fragment.app.FragmentTransaction);
-    method public abstract void onTabUnselected(androidx.appcompat.app.ActionBar.Tab, androidx.fragment.app.FragmentTransaction);
-  }
-
-  public class ActionBarDrawerToggle implements androidx.drawerlayout.widget.DrawerLayout.DrawerListener {
-    ctor public ActionBarDrawerToggle(android.app.Activity, androidx.drawerlayout.widget.DrawerLayout, int, int);
-    ctor public ActionBarDrawerToggle(android.app.Activity, androidx.drawerlayout.widget.DrawerLayout, androidx.appcompat.widget.Toolbar, int, int);
-    method public androidx.appcompat.graphics.drawable.DrawerArrowDrawable getDrawerArrowDrawable();
-    method public android.view.View.OnClickListener getToolbarNavigationClickListener();
-    method public boolean isDrawerIndicatorEnabled();
-    method public boolean isDrawerSlideAnimationEnabled();
-    method public void onConfigurationChanged(android.content.res.Configuration);
-    method public void onDrawerClosed(android.view.View);
-    method public void onDrawerOpened(android.view.View);
-    method public void onDrawerSlide(android.view.View, float);
-    method public void onDrawerStateChanged(int);
-    method public boolean onOptionsItemSelected(android.view.MenuItem);
-    method public void setDrawerArrowDrawable(androidx.appcompat.graphics.drawable.DrawerArrowDrawable);
-    method public void setDrawerIndicatorEnabled(boolean);
-    method public void setDrawerSlideAnimationEnabled(boolean);
-    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
-    method public void setHomeAsUpIndicator(int);
-    method public void setToolbarNavigationClickListener(android.view.View.OnClickListener);
-    method public void syncState();
-  }
-
-  public static abstract interface ActionBarDrawerToggle.Delegate {
-    method public abstract android.content.Context getActionBarThemedContext();
-    method public abstract android.graphics.drawable.Drawable getThemeUpIndicator();
-    method public abstract boolean isNavigationVisible();
-    method public abstract void setActionBarDescription(int);
-    method public abstract void setActionBarUpIndicator(android.graphics.drawable.Drawable, int);
-  }
-
-  public static abstract interface ActionBarDrawerToggle.DelegateProvider {
-    method public abstract androidx.appcompat.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
-  }
-
-  public class AlertDialog extends androidx.appcompat.app.AppCompatDialog implements android.content.DialogInterface {
-    ctor protected AlertDialog(android.content.Context);
-    ctor protected AlertDialog(android.content.Context, int);
-    ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-    method public android.widget.Button getButton(int);
-    method public android.widget.ListView getListView();
-    method public void setButton(int, java.lang.CharSequence, android.os.Message);
-    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public void setButton(int, java.lang.CharSequence, android.graphics.drawable.Drawable, android.content.DialogInterface.OnClickListener);
-    method public void setCustomTitle(android.view.View);
-    method public void setIcon(int);
-    method public void setIcon(android.graphics.drawable.Drawable);
-    method public void setIconAttribute(int);
-    method public void setMessage(java.lang.CharSequence);
-    method public void setView(android.view.View);
-    method public void setView(android.view.View, int, int, int, int);
-  }
-
-  public static class AlertDialog.Builder {
-    ctor public AlertDialog.Builder(android.content.Context);
-    ctor public AlertDialog.Builder(android.content.Context, int);
-    method public androidx.appcompat.app.AlertDialog create();
-    method public android.content.Context getContext();
-    method public androidx.appcompat.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setCancelable(boolean);
-    method public androidx.appcompat.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
-    method public androidx.appcompat.app.AlertDialog.Builder setCustomTitle(android.view.View);
-    method public androidx.appcompat.app.AlertDialog.Builder setIcon(int);
-    method public androidx.appcompat.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
-    method public androidx.appcompat.app.AlertDialog.Builder setIconAttribute(int);
-    method public deprecated androidx.appcompat.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
-    method public androidx.appcompat.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setMessage(int);
-    method public androidx.appcompat.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
-    method public androidx.appcompat.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setNegativeButtonIcon(android.graphics.drawable.Drawable);
-    method public androidx.appcompat.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setNeutralButtonIcon(android.graphics.drawable.Drawable);
-    method public androidx.appcompat.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setPositiveButtonIcon(android.graphics.drawable.Drawable);
-    method public androidx.appcompat.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
-    method public androidx.appcompat.app.AlertDialog.Builder setTitle(int);
-    method public androidx.appcompat.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
-    method public androidx.appcompat.app.AlertDialog.Builder setView(int);
-    method public androidx.appcompat.app.AlertDialog.Builder setView(android.view.View);
-    method public androidx.appcompat.app.AlertDialog show();
-  }
-
-  public class AppCompatActivity extends androidx.fragment.app.FragmentActivity implements androidx.appcompat.app.ActionBarDrawerToggle.DelegateProvider androidx.appcompat.app.AppCompatCallback androidx.core.app.TaskStackBuilder.SupportParentable {
-    ctor public AppCompatActivity();
-    method public androidx.appcompat.app.AppCompatDelegate getDelegate();
-    method public androidx.appcompat.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
-    method public androidx.appcompat.app.ActionBar getSupportActionBar();
-    method public android.content.Intent getSupportParentActivityIntent();
-    method public void onCreateSupportNavigateUpTaskStack(androidx.core.app.TaskStackBuilder);
-    method public final boolean onMenuItemSelected(int, android.view.MenuItem);
-    method public void onPrepareSupportNavigateUpTaskStack(androidx.core.app.TaskStackBuilder);
-    method public void onSupportActionModeFinished(androidx.appcompat.view.ActionMode);
-    method public void onSupportActionModeStarted(androidx.appcompat.view.ActionMode);
-    method public deprecated void onSupportContentChanged();
-    method public boolean onSupportNavigateUp();
-    method public androidx.appcompat.view.ActionMode onWindowStartingSupportActionMode(androidx.appcompat.view.ActionMode.Callback);
-    method public void setSupportActionBar(androidx.appcompat.widget.Toolbar);
-    method public deprecated void setSupportProgress(int);
-    method public deprecated void setSupportProgressBarIndeterminate(boolean);
-    method public deprecated void setSupportProgressBarIndeterminateVisibility(boolean);
-    method public deprecated void setSupportProgressBarVisibility(boolean);
-    method public androidx.appcompat.view.ActionMode startSupportActionMode(androidx.appcompat.view.ActionMode.Callback);
-    method public void supportInvalidateOptionsMenu();
-    method public void supportNavigateUpTo(android.content.Intent);
-    method public boolean supportRequestWindowFeature(int);
-    method public boolean supportShouldUpRecreateTask(android.content.Intent);
-  }
-
-  public abstract interface AppCompatCallback {
-    method public abstract void onSupportActionModeFinished(androidx.appcompat.view.ActionMode);
-    method public abstract void onSupportActionModeStarted(androidx.appcompat.view.ActionMode);
-    method public abstract androidx.appcompat.view.ActionMode onWindowStartingSupportActionMode(androidx.appcompat.view.ActionMode.Callback);
-  }
-
-  public abstract class AppCompatDelegate {
-    method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
-    method public abstract boolean applyDayNight();
-    method public static androidx.appcompat.app.AppCompatDelegate create(android.app.Activity, androidx.appcompat.app.AppCompatCallback);
-    method public static androidx.appcompat.app.AppCompatDelegate create(android.app.Dialog, androidx.appcompat.app.AppCompatCallback);
-    method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
-    method public abstract <T extends android.view.View> T findViewById(int);
-    method public static int getDefaultNightMode();
-    method public abstract androidx.appcompat.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
-    method public abstract android.view.MenuInflater getMenuInflater();
-    method public abstract androidx.appcompat.app.ActionBar getSupportActionBar();
-    method public abstract boolean hasWindowFeature(int);
-    method public abstract void installViewFactory();
-    method public abstract void invalidateOptionsMenu();
-    method public static boolean isCompatVectorFromResourcesEnabled();
-    method public abstract boolean isHandleNativeActionModesEnabled();
-    method public abstract void onConfigurationChanged(android.content.res.Configuration);
-    method public abstract void onCreate(android.os.Bundle);
-    method public abstract void onDestroy();
-    method public abstract void onPostCreate(android.os.Bundle);
-    method public abstract void onPostResume();
-    method public abstract void onSaveInstanceState(android.os.Bundle);
-    method public abstract void onStart();
-    method public abstract void onStop();
-    method public abstract boolean requestWindowFeature(int);
-    method public static void setCompatVectorFromResourcesEnabled(boolean);
-    method public abstract void setContentView(android.view.View);
-    method public abstract void setContentView(int);
-    method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
-    method public static void setDefaultNightMode(int);
-    method public abstract void setHandleNativeActionModesEnabled(boolean);
-    method public abstract void setLocalNightMode(int);
-    method public abstract void setSupportActionBar(androidx.appcompat.widget.Toolbar);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract androidx.appcompat.view.ActionMode startSupportActionMode(androidx.appcompat.view.ActionMode.Callback);
-    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
-    field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
-    field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
-    field public static final int MODE_NIGHT_AUTO = 0; // 0x0
-    field public static final int MODE_NIGHT_FOLLOW_SYSTEM = -1; // 0xffffffff
-    field public static final int MODE_NIGHT_NO = 1; // 0x1
-    field public static final int MODE_NIGHT_YES = 2; // 0x2
-  }
-
-  public class AppCompatDialog extends android.app.Dialog implements androidx.appcompat.app.AppCompatCallback {
-    ctor public AppCompatDialog(android.content.Context);
-    ctor public AppCompatDialog(android.content.Context, int);
-    ctor protected AppCompatDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-    method public androidx.appcompat.app.AppCompatDelegate getDelegate();
-    method public androidx.appcompat.app.ActionBar getSupportActionBar();
-    method public void onSupportActionModeFinished(androidx.appcompat.view.ActionMode);
-    method public void onSupportActionModeStarted(androidx.appcompat.view.ActionMode);
-    method public androidx.appcompat.view.ActionMode onWindowStartingSupportActionMode(androidx.appcompat.view.ActionMode.Callback);
-    method public boolean supportRequestWindowFeature(int);
-  }
-
-  public class AppCompatDialogFragment extends androidx.fragment.app.DialogFragment {
-    ctor public AppCompatDialogFragment();
-  }
-
-  public class AppCompatViewInflater {
-    ctor public AppCompatViewInflater();
-    method protected androidx.appcompat.widget.AppCompatAutoCompleteTextView createAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatButton createButton(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatCheckBox createCheckBox(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatCheckedTextView createCheckedTextView(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatEditText createEditText(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatImageButton createImageButton(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatImageView createImageView(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView createMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatRadioButton createRadioButton(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatRatingBar createRatingBar(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatSeekBar createSeekBar(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatSpinner createSpinner(android.content.Context, android.util.AttributeSet);
-    method protected androidx.appcompat.widget.AppCompatTextView createTextView(android.content.Context, android.util.AttributeSet);
-    method protected android.view.View createView(android.content.Context, java.lang.String, android.util.AttributeSet);
-  }
-
-}
-
-package androidx.appcompat.content.res {
-
-  public final class AppCompatResources {
-    method public static android.content.res.ColorStateList getColorStateList(android.content.Context, int);
-    method public static android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
-  }
-
-}
-
-package androidx.appcompat.graphics.drawable {
-
-  public class DrawerArrowDrawable extends android.graphics.drawable.Drawable {
-    ctor public DrawerArrowDrawable(android.content.Context);
-    method public void draw(android.graphics.Canvas);
-    method public float getArrowHeadLength();
-    method public float getArrowShaftLength();
-    method public float getBarLength();
-    method public float getBarThickness();
-    method public int getColor();
-    method public int getDirection();
-    method public float getGapSize();
-    method public int getOpacity();
-    method public final android.graphics.Paint getPaint();
-    method public float getProgress();
-    method public boolean isSpinEnabled();
-    method public void setAlpha(int);
-    method public void setArrowHeadLength(float);
-    method public void setArrowShaftLength(float);
-    method public void setBarLength(float);
-    method public void setBarThickness(float);
-    method public void setColor(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setDirection(int);
-    method public void setGapSize(float);
-    method public void setProgress(float);
-    method public void setSpinEnabled(boolean);
-    method public void setVerticalMirror(boolean);
-    field public static final int ARROW_DIRECTION_END = 3; // 0x3
-    field public static final int ARROW_DIRECTION_LEFT = 0; // 0x0
-    field public static final int ARROW_DIRECTION_RIGHT = 1; // 0x1
-    field public static final int ARROW_DIRECTION_START = 2; // 0x2
-  }
-
-}
-
-package androidx.appcompat.view {
-
-  public abstract class ActionMode {
-    ctor public ActionMode();
-    method public abstract void finish();
-    method public abstract android.view.View getCustomView();
-    method public abstract android.view.Menu getMenu();
-    method public abstract android.view.MenuInflater getMenuInflater();
-    method public abstract java.lang.CharSequence getSubtitle();
-    method public java.lang.Object getTag();
-    method public abstract java.lang.CharSequence getTitle();
-    method public boolean getTitleOptionalHint();
-    method public abstract void invalidate();
-    method public boolean isTitleOptional();
-    method public abstract void setCustomView(android.view.View);
-    method public abstract void setSubtitle(java.lang.CharSequence);
-    method public abstract void setSubtitle(int);
-    method public void setTag(java.lang.Object);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void setTitle(int);
-    method public void setTitleOptionalHint(boolean);
-  }
-
-  public static abstract interface ActionMode.Callback {
-    method public abstract boolean onActionItemClicked(androidx.appcompat.view.ActionMode, android.view.MenuItem);
-    method public abstract boolean onCreateActionMode(androidx.appcompat.view.ActionMode, android.view.Menu);
-    method public abstract void onDestroyActionMode(androidx.appcompat.view.ActionMode);
-    method public abstract boolean onPrepareActionMode(androidx.appcompat.view.ActionMode, android.view.Menu);
-  }
-
-  public abstract interface CollapsibleActionView {
-    method public abstract void onActionViewCollapsed();
-    method public abstract void onActionViewExpanded();
-  }
-
-  public class ContextThemeWrapper extends android.content.ContextWrapper {
-    ctor public ContextThemeWrapper();
-    ctor public ContextThemeWrapper(android.content.Context, int);
-    ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme);
-    method public void applyOverrideConfiguration(android.content.res.Configuration);
-    method public int getThemeResId();
-    method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
-  }
-
-}
-
-package androidx.appcompat.widget {
-
-  public class ActionMenuView extends androidx.appcompat.widget.LinearLayoutCompat {
-    ctor public ActionMenuView(android.content.Context);
-    ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
-    method public void dismissPopupMenus();
-    method protected androidx.appcompat.widget.ActionMenuView.LayoutParams generateDefaultLayoutParams();
-    method public androidx.appcompat.widget.ActionMenuView.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected androidx.appcompat.widget.ActionMenuView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public android.view.Menu getMenu();
-    method public android.graphics.drawable.Drawable getOverflowIcon();
-    method public int getPopupTheme();
-    method public boolean hideOverflowMenu();
-    method public boolean isOverflowMenuShowing();
-    method public void onConfigurationChanged(android.content.res.Configuration);
-    method public void onDetachedFromWindow();
-    method public void setOnMenuItemClickListener(androidx.appcompat.widget.ActionMenuView.OnMenuItemClickListener);
-    method public void setOverflowIcon(android.graphics.drawable.Drawable);
-    method public void setPopupTheme(int);
-    method public boolean showOverflowMenu();
-  }
-
-  public static class ActionMenuView.LayoutParams extends androidx.appcompat.widget.LinearLayoutCompat.LayoutParams {
-    ctor public ActionMenuView.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public ActionMenuView.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public ActionMenuView.LayoutParams(androidx.appcompat.widget.ActionMenuView.LayoutParams);
-    ctor public ActionMenuView.LayoutParams(int, int);
-    field public int cellsUsed;
-    field public boolean expandable;
-    field public int extraPixels;
-    field public boolean isOverflowButton;
-    field public boolean preventEdgeOffset;
-  }
-
-  public static abstract interface ActionMenuView.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
-  }
-
-  public class AppCompatAutoCompleteTextView extends android.widget.AutoCompleteTextView implements androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatAutoCompleteTextView(android.content.Context);
-    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class AppCompatButton extends android.widget.Button implements androidx.core.widget.AutoSizeableTextView androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatButton(android.content.Context);
-    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportAllCaps(boolean);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class AppCompatCheckBox extends android.widget.CheckBox implements androidx.core.widget.TintableCompoundButton {
-    ctor public AppCompatCheckBox(android.content.Context);
-    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatCheckBox(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportButtonTintList();
-    method public android.graphics.PorterDuff.Mode getSupportButtonTintMode();
-    method public void setSupportButtonTintList(android.content.res.ColorStateList);
-    method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
-    ctor public AppCompatCheckedTextView(android.content.Context);
-    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet, int);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class AppCompatEditText extends android.widget.EditText implements androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatEditText(android.content.Context);
-    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatEditText(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class AppCompatImageButton extends android.widget.ImageButton implements androidx.core.view.TintableBackgroundView androidx.core.widget.TintableImageSourceView {
-    ctor public AppCompatImageButton(android.content.Context);
-    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatImageButton(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public android.content.res.ColorStateList getSupportImageTintList();
-    method public android.graphics.PorterDuff.Mode getSupportImageTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setSupportImageTintList(android.content.res.ColorStateList);
-    method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public class AppCompatImageView extends android.widget.ImageView implements androidx.core.view.TintableBackgroundView androidx.core.widget.TintableImageSourceView {
-    ctor public AppCompatImageView(android.content.Context);
-    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatImageView(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public android.content.res.ColorStateList getSupportImageTintList();
-    method public android.graphics.PorterDuff.Mode getSupportImageTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setSupportImageTintList(android.content.res.ColorStateList);
-    method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public class AppCompatMultiAutoCompleteTextView extends android.widget.MultiAutoCompleteTextView implements androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context);
-    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatMultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class AppCompatRadioButton extends android.widget.RadioButton implements androidx.core.widget.TintableCompoundButton {
-    ctor public AppCompatRadioButton(android.content.Context);
-    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatRadioButton(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportButtonTintList();
-    method public android.graphics.PorterDuff.Mode getSupportButtonTintMode();
-    method public void setSupportButtonTintList(android.content.res.ColorStateList);
-    method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public class AppCompatRatingBar extends android.widget.RatingBar {
-    ctor public AppCompatRatingBar(android.content.Context);
-    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatRatingBar(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class AppCompatSeekBar extends android.widget.SeekBar {
-    ctor public AppCompatSeekBar(android.content.Context);
-    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatSeekBar(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class AppCompatSpinner extends android.widget.Spinner implements androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatSpinner(android.content.Context);
-    ctor public AppCompatSpinner(android.content.Context, int);
-    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
-    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public class AppCompatTextView extends android.widget.TextView implements androidx.core.widget.AutoSizeableTextView androidx.core.view.TintableBackgroundView {
-    ctor public AppCompatTextView(android.content.Context);
-    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet);
-    ctor public AppCompatTextView(android.content.Context, android.util.AttributeSet, int);
-    method public android.content.res.ColorStateList getSupportBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getSupportBackgroundTintMode();
-    method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setSupportBackgroundTintList(android.content.res.ColorStateList);
-    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTextAppearance(android.content.Context, int);
-  }
-
-  public class LinearLayoutCompat extends android.view.ViewGroup {
-    ctor public LinearLayoutCompat(android.content.Context);
-    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet);
-    ctor public LinearLayoutCompat(android.content.Context, android.util.AttributeSet, int);
-    method protected androidx.appcompat.widget.LinearLayoutCompat.LayoutParams generateDefaultLayoutParams();
-    method public androidx.appcompat.widget.LinearLayoutCompat.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected androidx.appcompat.widget.LinearLayoutCompat.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getBaselineAlignedChildIndex();
-    method public android.graphics.drawable.Drawable getDividerDrawable();
-    method public int getDividerPadding();
-    method public int getGravity();
-    method public int getOrientation();
-    method public int getShowDividers();
-    method public float getWeightSum();
-    method public boolean isBaselineAligned();
-    method public boolean isMeasureWithLargestChildEnabled();
-    method public void setBaselineAligned(boolean);
-    method public void setBaselineAlignedChildIndex(int);
-    method public void setDividerDrawable(android.graphics.drawable.Drawable);
-    method public void setDividerPadding(int);
-    method public void setGravity(int);
-    method public void setHorizontalGravity(int);
-    method public void setMeasureWithLargestChildEnabled(boolean);
-    method public void setOrientation(int);
-    method public void setShowDividers(int);
-    method public void setVerticalGravity(int);
-    method public void setWeightSum(float);
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int SHOW_DIVIDER_BEGINNING = 1; // 0x1
-    field public static final int SHOW_DIVIDER_END = 4; // 0x4
-    field public static final int SHOW_DIVIDER_MIDDLE = 2; // 0x2
-    field public static final int SHOW_DIVIDER_NONE = 0; // 0x0
-    field public static final int VERTICAL = 1; // 0x1
-  }
-
-  public static class LinearLayoutCompat.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public LinearLayoutCompat.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public LinearLayoutCompat.LayoutParams(int, int);
-    ctor public LinearLayoutCompat.LayoutParams(int, int, float);
-    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public LinearLayoutCompat.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public LinearLayoutCompat.LayoutParams(androidx.appcompat.widget.LinearLayoutCompat.LayoutParams);
-    field public int gravity;
-    field public float weight;
-  }
-
-  public class ListPopupWindow {
-    ctor public ListPopupWindow(android.content.Context);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
-    method public void clearListSelection();
-    method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
-    method public void dismiss();
-    method public android.view.View getAnchorView();
-    method public int getAnimationStyle();
-    method public android.graphics.drawable.Drawable getBackground();
-    method public int getHeight();
-    method public int getHorizontalOffset();
-    method public int getInputMethodMode();
-    method public android.widget.ListView getListView();
-    method public int getPromptPosition();
-    method public java.lang.Object getSelectedItem();
-    method public long getSelectedItemId();
-    method public int getSelectedItemPosition();
-    method public android.view.View getSelectedView();
-    method public int getSoftInputMode();
-    method public int getVerticalOffset();
-    method public int getWidth();
-    method public boolean isInputMethodNotNeeded();
-    method public boolean isModal();
-    method public boolean isShowing();
-    method public boolean onKeyDown(int, android.view.KeyEvent);
-    method public boolean onKeyPreIme(int, android.view.KeyEvent);
-    method public boolean onKeyUp(int, android.view.KeyEvent);
-    method public boolean performItemClick(int);
-    method public void postShow();
-    method public void setAdapter(android.widget.ListAdapter);
-    method public void setAnchorView(android.view.View);
-    method public void setAnimationStyle(int);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setContentWidth(int);
-    method public void setDropDownGravity(int);
-    method public void setHeight(int);
-    method public void setHorizontalOffset(int);
-    method public void setInputMethodMode(int);
-    method public void setListSelector(android.graphics.drawable.Drawable);
-    method public void setModal(boolean);
-    method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
-    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
-    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
-    method public void setPromptPosition(int);
-    method public void setPromptView(android.view.View);
-    method public void setSelection(int);
-    method public void setSoftInputMode(int);
-    method public void setVerticalOffset(int);
-    method public void setWidth(int);
-    method public void setWindowLayoutType(int);
-    method public void show();
-    field public static final int INPUT_METHOD_FROM_FOCUSABLE = 0; // 0x0
-    field public static final int INPUT_METHOD_NEEDED = 1; // 0x1
-    field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
-    field public static final int MATCH_PARENT = -1; // 0xffffffff
-    field public static final int POSITION_PROMPT_ABOVE = 0; // 0x0
-    field public static final int POSITION_PROMPT_BELOW = 1; // 0x1
-    field public static final int WRAP_CONTENT = -2; // 0xfffffffe
-  }
-
-  public class PopupMenu {
-    ctor public PopupMenu(android.content.Context, android.view.View);
-    ctor public PopupMenu(android.content.Context, android.view.View, int);
-    ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
-    method public void dismiss();
-    method public android.view.View.OnTouchListener getDragToOpenListener();
-    method public int getGravity();
-    method public android.view.Menu getMenu();
-    method public android.view.MenuInflater getMenuInflater();
-    method public void inflate(int);
-    method public void setGravity(int);
-    method public void setOnDismissListener(androidx.appcompat.widget.PopupMenu.OnDismissListener);
-    method public void setOnMenuItemClickListener(androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener);
-    method public void show();
-  }
-
-  public static abstract interface PopupMenu.OnDismissListener {
-    method public abstract void onDismiss(androidx.appcompat.widget.PopupMenu);
-  }
-
-  public static abstract interface PopupMenu.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
-  }
-
-  public class SearchView extends androidx.appcompat.widget.LinearLayoutCompat implements androidx.appcompat.view.CollapsibleActionView {
-    ctor public SearchView(android.content.Context);
-    ctor public SearchView(android.content.Context, android.util.AttributeSet);
-    ctor public SearchView(android.content.Context, android.util.AttributeSet, int);
-    method public int getImeOptions();
-    method public int getInputType();
-    method public int getMaxWidth();
-    method public java.lang.CharSequence getQuery();
-    method public java.lang.CharSequence getQueryHint();
-    method public androidx.cursoradapter.widget.CursorAdapter getSuggestionsAdapter();
-    method public boolean isIconfiedByDefault();
-    method public boolean isIconified();
-    method public boolean isQueryRefinementEnabled();
-    method public boolean isSubmitButtonEnabled();
-    method public void onActionViewCollapsed();
-    method public void onActionViewExpanded();
-    method public void setIconified(boolean);
-    method public void setIconifiedByDefault(boolean);
-    method public void setImeOptions(int);
-    method public void setInputType(int);
-    method public void setMaxWidth(int);
-    method public void setOnCloseListener(androidx.appcompat.widget.SearchView.OnCloseListener);
-    method public void setOnQueryTextFocusChangeListener(android.view.View.OnFocusChangeListener);
-    method public void setOnQueryTextListener(androidx.appcompat.widget.SearchView.OnQueryTextListener);
-    method public void setOnSearchClickListener(android.view.View.OnClickListener);
-    method public void setOnSuggestionListener(androidx.appcompat.widget.SearchView.OnSuggestionListener);
-    method public void setQuery(java.lang.CharSequence, boolean);
-    method public void setQueryHint(java.lang.CharSequence);
-    method public void setQueryRefinementEnabled(boolean);
-    method public void setSearchableInfo(android.app.SearchableInfo);
-    method public void setSubmitButtonEnabled(boolean);
-    method public void setSuggestionsAdapter(androidx.cursoradapter.widget.CursorAdapter);
-  }
-
-  public static abstract interface SearchView.OnCloseListener {
-    method public abstract boolean onClose();
-  }
-
-  public static abstract interface SearchView.OnQueryTextListener {
-    method public abstract boolean onQueryTextChange(java.lang.String);
-    method public abstract boolean onQueryTextSubmit(java.lang.String);
-  }
-
-  public static abstract interface SearchView.OnSuggestionListener {
-    method public abstract boolean onSuggestionClick(int);
-    method public abstract boolean onSuggestionSelect(int);
-  }
-
-  public class ShareActionProvider extends androidx.core.view.ActionProvider {
-    ctor public ShareActionProvider(android.content.Context);
-    method public android.view.View onCreateActionView();
-    method public void setOnShareTargetSelectedListener(androidx.appcompat.widget.ShareActionProvider.OnShareTargetSelectedListener);
-    method public void setShareHistoryFileName(java.lang.String);
-    method public void setShareIntent(android.content.Intent);
-    field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
-  }
-
-  public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
-    method public abstract boolean onShareTargetSelected(androidx.appcompat.widget.ShareActionProvider, android.content.Intent);
-  }
-
-  public class SwitchCompat extends android.widget.CompoundButton {
-    ctor public SwitchCompat(android.content.Context);
-    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchCompat(android.content.Context, android.util.AttributeSet, int);
-    method public boolean getShowText();
-    method public boolean getSplitTrack();
-    method public int getSwitchMinWidth();
-    method public int getSwitchPadding();
-    method public java.lang.CharSequence getTextOff();
-    method public java.lang.CharSequence getTextOn();
-    method public android.graphics.drawable.Drawable getThumbDrawable();
-    method public int getThumbTextPadding();
-    method public android.content.res.ColorStateList getThumbTintList();
-    method public android.graphics.PorterDuff.Mode getThumbTintMode();
-    method public android.graphics.drawable.Drawable getTrackDrawable();
-    method public android.content.res.ColorStateList getTrackTintList();
-    method public android.graphics.PorterDuff.Mode getTrackTintMode();
-    method public void onMeasure(int, int);
-    method public void setShowText(boolean);
-    method public void setSplitTrack(boolean);
-    method public void setSwitchMinWidth(int);
-    method public void setSwitchPadding(int);
-    method public void setSwitchTextAppearance(android.content.Context, int);
-    method public void setSwitchTypeface(android.graphics.Typeface, int);
-    method public void setSwitchTypeface(android.graphics.Typeface);
-    method public void setTextOff(java.lang.CharSequence);
-    method public void setTextOn(java.lang.CharSequence);
-    method public void setThumbDrawable(android.graphics.drawable.Drawable);
-    method public void setThumbResource(int);
-    method public void setThumbTextPadding(int);
-    method public void setThumbTintList(android.content.res.ColorStateList);
-    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTrackDrawable(android.graphics.drawable.Drawable);
-    method public void setTrackResource(int);
-    method public void setTrackTintList(android.content.res.ColorStateList);
-    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
-  }
-
-  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
-    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
-    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
-  }
-
-  public static final class ThemedSpinnerAdapter.Helper {
-    ctor public ThemedSpinnerAdapter.Helper(android.content.Context);
-    method public android.view.LayoutInflater getDropDownViewInflater();
-    method public android.content.res.Resources.Theme getDropDownViewTheme();
-    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
-  }
-
-  public class Toolbar extends android.view.ViewGroup {
-    ctor public Toolbar(android.content.Context);
-    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
-    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
-    method public void collapseActionView();
-    method public void dismissPopupMenus();
-    method protected androidx.appcompat.widget.Toolbar.LayoutParams generateDefaultLayoutParams();
-    method public androidx.appcompat.widget.Toolbar.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected androidx.appcompat.widget.Toolbar.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getContentInsetEnd();
-    method public int getContentInsetEndWithActions();
-    method public int getContentInsetLeft();
-    method public int getContentInsetRight();
-    method public int getContentInsetStart();
-    method public int getContentInsetStartWithNavigation();
-    method public int getCurrentContentInsetEnd();
-    method public int getCurrentContentInsetLeft();
-    method public int getCurrentContentInsetRight();
-    method public int getCurrentContentInsetStart();
-    method public android.graphics.drawable.Drawable getLogo();
-    method public java.lang.CharSequence getLogoDescription();
-    method public android.view.Menu getMenu();
-    method public java.lang.CharSequence getNavigationContentDescription();
-    method public android.graphics.drawable.Drawable getNavigationIcon();
-    method public android.graphics.drawable.Drawable getOverflowIcon();
-    method public int getPopupTheme();
-    method public java.lang.CharSequence getSubtitle();
-    method public java.lang.CharSequence getTitle();
-    method public int getTitleMarginBottom();
-    method public int getTitleMarginEnd();
-    method public int getTitleMarginStart();
-    method public int getTitleMarginTop();
-    method public boolean hasExpandedActionView();
-    method public boolean hideOverflowMenu();
-    method public void inflateMenu(int);
-    method public boolean isOverflowMenuShowing();
-    method public void setContentInsetEndWithActions(int);
-    method public void setContentInsetStartWithNavigation(int);
-    method public void setContentInsetsAbsolute(int, int);
-    method public void setContentInsetsRelative(int, int);
-    method public void setLogo(int);
-    method public void setLogo(android.graphics.drawable.Drawable);
-    method public void setLogoDescription(int);
-    method public void setLogoDescription(java.lang.CharSequence);
-    method public void setNavigationContentDescription(int);
-    method public void setNavigationContentDescription(java.lang.CharSequence);
-    method public void setNavigationIcon(int);
-    method public void setNavigationIcon(android.graphics.drawable.Drawable);
-    method public void setNavigationOnClickListener(android.view.View.OnClickListener);
-    method public void setOnMenuItemClickListener(androidx.appcompat.widget.Toolbar.OnMenuItemClickListener);
-    method public void setOverflowIcon(android.graphics.drawable.Drawable);
-    method public void setPopupTheme(int);
-    method public void setSubtitle(int);
-    method public void setSubtitle(java.lang.CharSequence);
-    method public void setSubtitleTextAppearance(android.content.Context, int);
-    method public void setSubtitleTextColor(int);
-    method public void setTitle(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleMargin(int, int, int, int);
-    method public void setTitleMarginBottom(int);
-    method public void setTitleMarginEnd(int);
-    method public void setTitleMarginStart(int);
-    method public void setTitleMarginTop(int);
-    method public void setTitleTextAppearance(android.content.Context, int);
-    method public void setTitleTextColor(int);
-    method public boolean showOverflowMenu();
-  }
-
-  public static class Toolbar.LayoutParams extends androidx.appcompat.app.ActionBar.LayoutParams {
-    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public Toolbar.LayoutParams(int, int);
-    ctor public Toolbar.LayoutParams(int, int, int);
-    ctor public Toolbar.LayoutParams(int);
-    ctor public Toolbar.LayoutParams(androidx.appcompat.widget.Toolbar.LayoutParams);
-    ctor public Toolbar.LayoutParams(androidx.appcompat.app.ActionBar.LayoutParams);
-    ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
-  }
-
-  public static abstract interface Toolbar.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
-  }
-
-  public static class Toolbar.SavedState extends androidx.customview.view.AbsSavedState {
-    ctor public Toolbar.SavedState(android.os.Parcel);
-    ctor public Toolbar.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public Toolbar.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<androidx.appcompat.widget.Toolbar.SavedState> CREATOR;
-  }
-
-  public class TooltipCompat {
-    method public static void setTooltipText(android.view.View, java.lang.CharSequence);
-  }
-
-}
-
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
index 7dfbbd3..d44fe399 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothGattCharacteristicTest.kt
@@ -17,6 +17,7 @@
 package androidx.bluetooth
 
 import android.bluetooth.BluetoothGattCharacteristic as FwkBluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor as FwkBluetoothGattDescriptor
 import java.util.UUID
 import org.junit.Assert
 import org.junit.Test
@@ -84,5 +85,24 @@
             Assert.assertEquals(fwkGattCharacteristic.uuid, gattCharacteristic.uuid)
             Assert.assertEquals(it.value, gattCharacteristic.permissions)
         }
+
+        val charUuid = UUID.randomUUID()
+        val fwkGattCharacteristic = FwkBluetoothGattCharacteristic(
+            charUuid,
+            /*properties=*/0, /*permissions=*/0
+        )
+        val descUuid1 = UUID.randomUUID()
+        val descUuid2 = UUID.randomUUID()
+
+        val desc1 = FwkBluetoothGattDescriptor(descUuid1, /*permission=*/0)
+        val desc2 = FwkBluetoothGattDescriptor(descUuid2, /*permission=*/0)
+        fwkGattCharacteristic.addDescriptor(desc1)
+        fwkGattCharacteristic.addDescriptor(desc2)
+
+        val characteristicWithDescriptors = BluetoothGattCharacteristic(fwkGattCharacteristic)
+
+        Assert.assertEquals(2, characteristicWithDescriptors.descriptors.size)
+        Assert.assertEquals(descUuid1, characteristicWithDescriptors.descriptors[0].uuid)
+        Assert.assertEquals(descUuid2, characteristicWithDescriptors.descriptors[1].uuid)
     }
 }
\ No newline at end of file
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
index 89b407b..eeb03b8 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattCharacteristic.kt
@@ -25,7 +25,7 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
 class BluetoothGattCharacteristic internal constructor(
-    internal var characteristic: FwkGattCharacteristic
+    internal var fwkCharacteristic: FwkGattCharacteristic
 ) {
     companion object {
         const val PROPERTY_BROADCAST = FwkGattCharacteristic.PROPERTY_BROADCAST
@@ -56,17 +56,23 @@
      * The UUID of the characteristic
      */
     val uuid: UUID
-        get() = characteristic.uuid
+        get() = fwkCharacteristic.uuid
 
     /**
      * The properties of the characteristic
      */
     val properties: Int
-        get() = characteristic.properties
+        get() = fwkCharacteristic.properties
 
     /**
      * The permissions for the characteristic
      */
     val permissions: Int
-        get() = characteristic.permissions
+        get() = fwkCharacteristic.permissions
+
+    /**
+     * A list of descriptors for the characteristic
+     */
+    val descriptors: List<BluetoothGattDescriptor> =
+        fwkCharacteristic.descriptors.map { BluetoothGattDescriptor(it) }
 }
\ No newline at end of file
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattDescriptor.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattDescriptor.kt
index 97d123a..62d7798 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattDescriptor.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothGattDescriptor.kt
@@ -32,17 +32,49 @@
     internal var fwkDescriptor: FwkBluetoothGattDescriptor
 ) {
     companion object {
+        /**
+         * The descriptor is readable
+         */
         const val PERMISSION_READ: Int = FwkBluetoothGattDescriptor.PERMISSION_READ
+
+        /**
+         * The descriptor is readable if encrypted
+         */
         const val PERMISSION_READ_ENCRYPTED: Int =
             FwkBluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED
+
+        /**
+         * The descriptor is readable if person-in-the-middle protection is enabled
+         */
         const val PERMISSION_READ_ENCRYPTED_MITM: Int =
             FwkBluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM
+
+        /**
+         * The descriptor is writable
+         */
         const val PERMISSION_WRITE: Int = FwkBluetoothGattDescriptor.PERMISSION_WRITE
+
+        /**
+         * The descriptor is writable if encrypted
+         */
         const val PERMISSION_WRITE_ENCRYPTED: Int =
             FwkBluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED
+
+        /**
+         * The descriptor is writable if person-in-the-middle protection is enabled
+         */
         const val PERMISSION_WRITE_ENCRYPTED_MITM: Int =
             FwkBluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM
+
+        /**
+         * The descriptor is writable if authentication signature is used
+         */
         const val PERMISSION_WRITE_SIGNED: Int = FwkBluetoothGattDescriptor.PERMISSION_WRITE_SIGNED
+
+        /**
+         * The descriptor is writable if person-in-the-middle protection is enabled
+         * and authentication signature is used
+         */
         const val PERMISSION_WRITE_SIGNED_MITM: Int =
             FwkBluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM
     }
@@ -55,6 +87,11 @@
 
     /**
      * The permissions for the descriptor.
+     *
+     * It is a combination of [PERMISSION_READ], [PERMISSION_READ_ENCRYPTED],
+     * [PERMISSION_READ_ENCRYPTED_MITM], [PERMISSION_WRITE], [PERMISSION_WRITE_ENCRYPTED],
+     * [PERMISSION_WRITE_ENCRYPTED_MITM], [PERMISSION_WRITE_SIGNED],
+     * and [PERMISSION_WRITE_SIGNED_MITM].
      */
     val permissions: Int
         get() = fwkDescriptor.permissions
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
index 25b43d8..1b38884 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/experimental/GattClientImpl.kt
@@ -41,6 +41,8 @@
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.job
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
 
 internal class GattClientImpl {
 
@@ -89,6 +91,7 @@
         val finished = Job(parent = coroutineContext.job)
         var currentTask: ClientTask? = null
         val subscribeMap: MutableMap<BluetoothGattCharacteristic, SubscribeListener> = arrayMapOf()
+        val subscribeMutex = Mutex()
 
         val callback = object : BluetoothGattCallback() {
             override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
@@ -154,8 +157,10 @@
                 characteristic: BluetoothGattCharacteristic,
                 value: ByteArray
             ) {
-                synchronized(subscribeMap) {
-                    subscribeMap[characteristic]?.onCharacteristicNotification(value)
+                launch {
+                    subscribeMutex.withLock {
+                        subscribeMap[characteristic]?.onCharacteristicNotification(value)
+                    }
                 }
             }
         }
@@ -262,7 +267,9 @@
                     }
 
                     this.awaitClose {
-                        unregisterSubscribeListener(characteristic)
+                        launch {
+                            unregisterSubscribeListener(characteristic)
+                        }
                         bluetoothGatt.setCharacteristicNotification(characteristic,
                             /*enable=*/false)
                         bluetoothGatt.writeDescriptor(
@@ -282,11 +289,11 @@
                 }
             }
 
-            private fun registerSubscribeListener(
+            private suspend fun registerSubscribeListener(
                 characteristic: BluetoothGattCharacteristic,
                 callback: SubscribeListener
             ): Boolean {
-                synchronized(subscribeMap) {
+                subscribeMutex.withLock {
                     if (subscribeMap.containsKey(characteristic)) {
                         return false
                     }
@@ -295,8 +302,10 @@
                 }
             }
 
-            private fun unregisterSubscribeListener(characteristic: BluetoothGattCharacteristic) {
-                synchronized(subscribeMap) {
+            private suspend fun unregisterSubscribeListener(
+                characteristic: BluetoothGattCharacteristic
+            ) {
+                subscribeMutex.withLock {
                     subscribeMap.remove(characteristic)
                 }
             }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
index 4313048..4dbe46e 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/ListTaskOutputsTask.kt
@@ -110,22 +110,10 @@
 
 // TODO(149103692): remove all elements of this set
 val taskNamesKnownToDuplicateOutputs = setOf(
-    "jarRelease",
-    "jarDebug",
     "kotlinSourcesJar",
     "releaseSourcesJar",
     "sourceJarRelease",
     "sourceJar",
-    // MPP plugin has issues with modules using withJava() clause, see b/158747039.
-    "processTestResources",
-    "jvmTestProcessResources",
-    "desktopTestProcessResources",
-    "processResources",
-    "jvmProcessResources",
-    "desktopProcessResources",
-    // https://github.com/square/wire/issues/1947
-    "generateDebugProtos",
-    "generateReleaseProtos",
     // Release APKs
     "copyReleaseApk",
     // The following tests intentionally have the same output of golden images
@@ -133,17 +121,11 @@
     "updateGoldenDebugUnitTest"
 )
 
-val taskTypesKnownToDuplicateOutputs = setOf(
-    // b/224564238
-    "com.android.build.gradle.internal.lint.AndroidLintTask_Decorated"
-)
-
 fun shouldValidateTaskOutput(task: Task): Boolean {
     if (!task.enabled) {
         return false
     }
-    return !taskNamesKnownToDuplicateOutputs.contains(task.name) &&
-        !taskTypesKnownToDuplicateOutputs.contains(task::class.qualifiedName)
+    return !taskNamesKnownToDuplicateOutputs.contains(task.name)
 }
 
 // For this project and all subprojects, collects all tasks and creates a map keyed by their output files
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
index 5f87fd4..761f4ea 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/metalava/MetalavaRunner.kt
@@ -46,6 +46,9 @@
         "--no-banner",
         "--hide",
         "HiddenSuperclass", // We allow having a hidden parent class
+        "--hide",
+        // Removing final from a method does not cause compatibility issues for AndroidX.
+        "RemovedFinalStrict",
 
         "--error",
         "UnresolvedImport",
diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
index 47d27e4..48287fe 100644
--- a/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
+++ b/buildSrc/public/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -25,7 +25,7 @@
     const val DEFAULT_MIN_SDK_VERSION = 14
     const val INSTRUMENTATION_RUNNER = "androidx.test.runner.AndroidJUnitRunner"
     private const val INTERNAL_BUILD_TOOLS_VERSION = "34.0.0-rc3"
-    private const val PUBLIC_BUILD_TOOLS_VERSION = "34.0.0-rc4"
+    private const val PUBLIC_BUILD_TOOLS_VERSION = "34.0.0"
     const val NDK_VERSION = "23.1.7779620"
 
     /**
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt
index f073a19..5e70155 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/compat/quirk/CloseCaptureSessionOnDisconnectQuirk.kt
@@ -61,11 +61,17 @@
                 //  switching to a new capture session may trigger camera HAL crashes. Add more
                 //  hardware platforms here when they're identified.
                 true
-            } else {
+            } else if (Build.MODEL.lowercase(Locale.getDefault()).startsWith("cph")) {
                 // For CPH devices, the shutdown sequence oftentimes triggers ANR for the test app.
                 // As a result, we need to close the capture session to stop the captures, then
                 // release the Surfaces by FinalizeSessionOnCloseQuirk.
-                return Build.MODEL.lowercase(Locale.getDefault()).startsWith("cph")
+                true
+            } else {
+                // For Infinix devices, there is a service that actively kills apps that use
+                // significant memory, including the _foreground_ test applications. Closing the
+                // capture session ensures that we finalize every CameraGraph session, slightly
+                // lowering the peak memory.
+                Build.BRAND.lowercase(Locale.getDefault()) == "infinix"
             }
         }
     }
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 d3a2e92..d4c2e51 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
@@ -65,6 +65,7 @@
 import androidx.camera.testing.fakes.FakeCamera
 import androidx.camera.testing.fakes.FakeUseCase
 import androidx.test.filters.MediumTest
+import androidx.testutils.MainDispatcherRule
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import com.google.common.util.concurrent.FutureCallback
@@ -75,19 +76,23 @@
 import java.util.concurrent.Executors
 import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
-import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.async
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.withContext
 import org.junit.After
 import org.junit.Assert.assertThrows
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.robolectric.annotation.Config
@@ -131,10 +136,25 @@
     240 + AREA_WIDTH_2 / 2, AREA_HEIGHT_2 / 2
 )
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(RobolectricCameraPipeTestRunner::class)
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 @DoNotInstrument
 class FocusMeteringControlTest {
+    private val testScope = TestScope()
+    private val testDispatcher = StandardTestDispatcher(testScope.testScheduler)
+
+    @get:Rule
+    val mainDispatcherRule = MainDispatcherRule(testDispatcher)
+
+    private val fakeUseCaseThreads by lazy {
+        UseCaseThreads(
+            testScope,
+            testDispatcher.asExecutor(),
+            testDispatcher
+        )
+    }
+
     private val pointFactory = SurfaceOrientedMeteringPointFactory(1f, 1f)
     private lateinit var focusMeteringControl: FocusMeteringControl
 
@@ -145,17 +165,6 @@
     private val cameraPropertiesMap = mutableMapOf<String, CameraProperties>()
 
     private val fakeRequestControl = FakeUseCaseCameraRequestControl()
-    private val fakeUseCaseThreads by lazy {
-        val executor = Executors.newSingleThreadExecutor()
-        val dispatcher = executor.asCoroutineDispatcher()
-        val cameraScope = CoroutineScope(Job() + dispatcher)
-
-        UseCaseThreads(
-            cameraScope,
-            executor,
-            dispatcher,
-        )
-    }
 
     @Before
     fun setUp() {
@@ -337,7 +346,7 @@
     }
 
     @Test
-    fun startFocusAndMetering_invalidPoint() = runBlocking {
+    fun startFocusAndMetering_invalidPoint() = runTest {
         val invalidPoint = pointFactory.createPoint(1f, 1.1f)
 
         val future = focusMeteringControl.startFocusAndMetering(
@@ -348,7 +357,7 @@
     }
 
     @Test
-    fun startFocusAndMetering_defaultPoint_3ARectsAreCorrect() = runBlocking {
+    fun startFocusAndMetering_defaultPoint_3ARectsAreCorrect() = runTest {
         startFocusMeteringAndAwait(FocusMeteringAction.Builder(point1).build())
 
         with(fakeRequestControl.focusMeteringCalls.last()) {
@@ -364,7 +373,7 @@
     }
 
     @Test
-    fun startFocusAndMetering_defaultPoint_3ALocksAreCorrect() = runBlocking {
+    fun startFocusAndMetering_defaultPoint_3ALocksAreCorrect() = runTest {
         startFocusMeteringAndAwait(FocusMeteringAction.Builder(point1).build())
 
         with(fakeRequestControl.focusMeteringCalls.last()) {
@@ -378,7 +387,7 @@
     }
 
     @Test
-    fun startFocusAndMetering_multiplePoints_3ARectsAreCorrect() = runBlocking {
+    fun startFocusAndMetering_multiplePoints_3ARectsAreCorrect() = runTest {
         // Camera 0 i.e. Max AF count = 3, Max AE count = 3, Max AWB count = 1
         startFocusMeteringAndAwait(
             FocusMeteringAction.Builder(point1)
@@ -452,7 +461,7 @@
     }
 
     @Test
-    fun startFocusAndMetering_multiplePointsVariousModes() = runBlocking {
+    fun startFocusAndMetering_multiplePointsVariousModes() = runTest {
         // Camera 0 i.e. Max AF count = 3, Max AE count = 3, Max AWB count = 1
         startFocusMeteringAndAwait(
             FocusMeteringAction.Builder(point1, FocusMeteringAction.FLAG_AWB)
@@ -698,7 +707,7 @@
     }
 
     @Test
-    fun startFocusMetering_AfLocked_completesWithFocusTrue() {
+    fun startFocusMetering_AfLocked_completesWithFocusTrue() = runTest {
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
             Result3A(
                 status = Result3A.Status.OK,
@@ -717,7 +726,7 @@
     }
 
     @Test
-    fun startFocusMetering_AfNotLocked_completesWithFocusFalse() {
+    fun startFocusMetering_AfNotLocked_completesWithFocusFalse() = runTest {
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
             Result3A(
                 status = Result3A.Status.OK,
@@ -736,7 +745,7 @@
     }
 
     @Test
-    fun startFocusMetering_AfStateIsNull_completesWithFocusTrue() {
+    fun startFocusMetering_AfStateIsNull_completesWithFocusTrue() = runTest {
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
             Result3A(
                 status = Result3A.Status.OK,
@@ -758,7 +767,7 @@
     }
 
     @Test
-    fun startFocusMeteringAfRequested_CameraNotSupportAfAuto_CompletesWithTrue() {
+    fun startFocusMeteringAfRequested_CameraNotSupportAfAuto_CompletesWithTrue() = runTest {
         // Use camera which does not support AF_AUTO
         focusMeteringControl = initFocusMeteringControl(CAMERA_ID_2)
         val action = FocusMeteringAction.Builder(point1)
@@ -774,7 +783,7 @@
     @MediumTest
     @Test
     fun startFocusMetering_cancelledBeforeCompletion_failsWithOperationCanceledOperation() =
-        runBlocking {
+        runTest {
             // Arrange. Set a delay CompletableDeferred
             fakeRequestControl.focusMeteringResult = CompletableDeferred<Result3A>().apply {
                 async(Dispatchers.Default) {
@@ -802,7 +811,7 @@
         }
 
     @Test
-    fun startThenCancelThenStart_previous2FuturesFailsWithOperationCanceled() {
+    fun startThenCancelThenStart_previous2FuturesFailsWithOperationCanceled() = runTest {
         // Arrange. Set a never complete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
         fakeRequestControl.cancelFocusMeteringResult = CompletableDeferred()
@@ -820,34 +829,36 @@
 
     @MediumTest
     @Test
-    fun startMultipleActions_allExceptLatestAreCancelled() = runBlocking {
-        // Arrange. Set a delay CompletableDeferred
-        fakeRequestControl.focusMeteringResult = CompletableDeferred<Result3A>().apply {
-            async(Dispatchers.Default) {
-                delay(500)
-                complete(
-                    Result3A(
-                        status = Result3A.Status.OK,
-                        frameMetadata = FakeFrameMetadata(
-                            extraMetadata = mapOf(
-                                CONTROL_AF_STATE to CONTROL_AF_STATE_FOCUSED_LOCKED
-                            )
-                        )
-                    )
-                )
-            }
-        }
+    fun startMultipleActions_allExceptLatestAreCancelled() = runTest {
+        // Arrange.
+        // Set a CompletableDeferred that is completed later
+        fakeRequestControl.focusMeteringResult = CompletableDeferred()
+
         val action = FocusMeteringAction.Builder(point1).build()
         val result1 = focusMeteringControl.startFocusAndMetering(action)
         val result2 = focusMeteringControl.startFocusAndMetering(action)
         val result3 = focusMeteringControl.startFocusAndMetering(action)
+
+        // Simulate CompletableDeferred completion is delayed and all tasks completing before then
+        advanceUntilIdle()
+        fakeRequestControl.focusMeteringResult.complete(
+            Result3A(
+                status = Result3A.Status.OK,
+                frameMetadata = FakeFrameMetadata(
+                    extraMetadata = mapOf(
+                        CONTROL_AF_STATE to CONTROL_AF_STATE_FOCUSED_LOCKED
+                    )
+                )
+            )
+        )
+
         assertFutureFailedWithOperationCancellation(result1)
         assertFutureFailedWithOperationCancellation(result2)
         assertFutureFocusCompleted(result3, true)
     }
 
     @Test
-    fun startFocusMetering_focusedThenCancel_futureStillCompletes() = runBlocking {
+    fun startFocusMetering_focusedThenCancel_futureStillCompletes() = runTest {
         // Arrange.
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
             Result3A(
@@ -862,6 +873,7 @@
         val action = FocusMeteringAction.Builder(point1).build()
 
         val result = focusMeteringControl.startFocusAndMetering(action).apply {
+            advanceUntilIdle()
             get(3, TimeUnit.SECONDS)
         }
 
@@ -873,7 +885,7 @@
     }
 
     @Test
-    fun startFocusMeteringAFAEAWB_noPointsAreSupported_failFuture() {
+    fun startFocusMeteringAFAEAWB_noPointsAreSupported_failFuture() = runTest {
         val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_3)
         val action = FocusMeteringAction.Builder(
             point1,
@@ -886,7 +898,7 @@
     }
 
     @Test
-    fun startFocusMeteringAEAWB_noPointsAreSupported_failFuture() {
+    fun startFocusMeteringAEAWB_noPointsAreSupported_failFuture() = runTest {
         val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_3)
         val action = FocusMeteringAction.Builder(
             point1,
@@ -898,7 +910,7 @@
     }
 
     @Test
-    fun startFocusMeteringAFAWB_noPointsAreSupported_failFuture() {
+    fun startFocusMeteringAFAWB_noPointsAreSupported_failFuture() = runTest {
         val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_3)
         val action = FocusMeteringAction.Builder(
             point1,
@@ -910,7 +922,7 @@
     }
 
     @Test
-    fun startFocusMetering_morePointsThanSupported_futureCompletes() {
+    fun startFocusMetering_morePointsThanSupported_futureCompletes() = runTest {
         // Camera 0 supports only 3 AF, 3 AE, 1 AWB regions, here we try to have 1 AE region, 2 AWB
         // regions. It should still complete the future, even though focus is not locked.
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
@@ -937,7 +949,7 @@
     }
 
     @Test
-    fun startFocusMetering_noPointsAreValid_failFuture() {
+    fun startFocusMetering_noPointsAreValid_failFuture() = runTest {
         val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_0)
 
         // These will generate MeteringRectangles (width == 0 or height ==0)
@@ -953,7 +965,7 @@
     }
 
     @Test
-    fun isFocusMeteringSupported_allSupportedPoints_shouldReturnTrue() {
+    fun isFocusMeteringSupported_allSupportedPoints_shouldReturnTrue() = runTest {
         val action = FocusMeteringAction.Builder(
             point1,
             FocusMeteringAction.FLAG_AF or FocusMeteringAction.FLAG_AE or
@@ -965,7 +977,7 @@
     }
 
     @Test
-    fun isFocusMeteringSupported_morePointsThanSupported_shouldReturnTrue() {
+    fun isFocusMeteringSupported_morePointsThanSupported_shouldReturnTrue() = runTest {
         // Camera 0 supports 3 AF, 3 AE, 1 AWB regions, here we try to have 1 AE region, 2 AWB
         // regions. But it should still be supported.
         val action = FocusMeteringAction.Builder(
@@ -978,7 +990,7 @@
     }
 
     @Test
-    fun isFocusMeteringSupported_noSupport3ARegion_shouldReturnFalse() {
+    fun isFocusMeteringSupported_noSupport3ARegion_shouldReturnFalse() = runTest {
         val action = FocusMeteringAction.Builder(point1).build()
 
         // No 3A regions are supported on Camera3
@@ -987,7 +999,7 @@
     }
 
     @Test
-    fun isFocusMeteringSupported_allInvalidPoints_shouldReturnFalse() {
+    fun isFocusMeteringSupported_allInvalidPoints_shouldReturnFalse() = runTest {
         val invalidPoint1 = pointFactory.createPoint(1.1f, 0f)
         val invalidPoint2 = pointFactory.createPoint(0f, 1.1f)
         val invalidPoint3 = pointFactory.createPoint(-0.1f, 0f)
@@ -1000,7 +1012,7 @@
     }
 
     @Test
-    fun cancelFocusMetering_actionIsCanceledAndFutureCompletes() {
+    fun cancelFocusMetering_actionIsCanceledAndFutureCompletes() = runTest {
         // Arrange. Set a never complete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
         val action = FocusMeteringAction.Builder(point1).build()
@@ -1016,7 +1028,7 @@
 
     @MediumTest
     @Test
-    fun cancelFocusAndMetering_autoCancelIsDisabled(): Unit = runBlocking {
+    fun cancelFocusAndMetering_autoCancelIsDisabled(): Unit = runTest {
         // Arrange. Set a never complete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
         val autoCancelDuration: Long = 500
@@ -1028,18 +1040,22 @@
 
         // Act. Call cancel before the auto cancel occur.
         focusMeteringControl.cancelFocusAndMeteringAsync().await()
+        advanceUntilIdle()
         assertThat(fakeRequestControl.cancelFocusMeteringCallCount).isEqualTo(1)
 
         // Assert. cancelFocusMetering only be invoked once.
         delay(autoFocusTimeoutDuration)
+        advanceUntilIdle()
         assertThat(fakeRequestControl.cancelFocusMeteringCallCount).isEqualTo(1)
     }
 
     @MediumTest
     @Test
-    fun autoCancelDuration_completeWithIsFocusSuccessfulFalse() {
-        // Arrange. Set a never complete CompletableDeferred
+    fun autoCancelDuration_completeWithIsFocusSuccessfulFalse() = runTest {
+        // Arrange.
+        // Set an incomplete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
+
         val autoCancelTimeOutDuration: Long = 500
         val action = FocusMeteringAction.Builder(point1)
             .setAutoCancelDuration(autoCancelTimeOutDuration, TimeUnit.MILLISECONDS)
@@ -1051,6 +1067,11 @@
             autoCancelTimeOutDuration
         )
 
+        // simulate UseCaseCamera timing out during auto focus
+        fakeRequestControl.focusMeteringResult.complete(
+            Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
+        )
+
         // Assert.
         assertFutureFocusCompleted(future, false)
     }
@@ -1058,15 +1079,15 @@
     @MediumTest
     @Test
     fun shorterAutoCancelDuration_cancelIsCalled_completeActionFutureIsNotCalled(): Unit =
-        runBlocking {
-            // Arrange. Set a never complete CompletableDeferred
+        runTest {
+            // Arrange.
+            // Set an incomplete CompletableDeferred
             fakeRequestControl.focusMeteringResult = CompletableDeferred()
             val autoCancelDuration: Long = 500
             val action = FocusMeteringAction.Builder(point1)
                 .setAutoCancelDuration(autoCancelDuration, TimeUnit.MILLISECONDS)
                 .build()
             val autoFocusTimeoutDuration: Long = 1000
-            focusMeteringControl.startFocusAndMetering(action, autoFocusTimeoutDuration)
 
             // Act.
             val future = focusMeteringControl.startFocusAndMetering(
@@ -1074,15 +1095,22 @@
                 autoFocusTimeoutDuration
             )
 
+            // simulate UseCaseCamera timing out during auto focus
+            fakeRequestControl.focusMeteringResult.complete(
+                Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
+            )
+
             // Assert.
             assertFutureFailedWithOperationCancellation(future)
         }
 
     @MediumTest
     @Test
-    fun longerAutoCancelDuration_completeWithIsFocusSuccessfulFalse() {
-        // Arrange. Set a never complete CompletableDeferred
+    fun longerAutoCancelDuration_completeWithIsFocusSuccessfulFalse() = runTest {
+        // Arrange.
+        // Set an incomplete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
+
         val autoCancelDuration: Long = 1000
         val action = FocusMeteringAction.Builder(point1)
             .setAutoCancelDuration(autoCancelDuration, TimeUnit.MILLISECONDS)
@@ -1092,15 +1120,22 @@
         // Act.
         val future = focusMeteringControl.startFocusAndMetering(action, autoFocusTimeoutDuration)
 
+        // simulate UseCaseCamera timing out during auto focus
+        fakeRequestControl.focusMeteringResult.complete(
+            Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
+        )
+
         // Assert.
         assertFutureFocusCompleted(future, false)
     }
 
     @MediumTest
     @Test
-    fun autoCancelDurationDisabled_completeAfterAutoFocusTimeoutDuration(): Unit = runBlocking {
-        // Arrange. Set a never complete CompletableDeferred
+    fun autoCancelDurationDisabled_completeAfterAutoFocusTimeoutDuration(): Unit = runTest {
+        // Arrange.
+        // Set an incomplete CompletableDeferred
         fakeRequestControl.focusMeteringResult = CompletableDeferred()
+
         val autoCancelDuration: Long = 500
         val action = FocusMeteringAction.Builder(point1)
             .setAutoCancelDuration(autoCancelDuration, TimeUnit.MILLISECONDS)
@@ -1113,12 +1148,17 @@
             action, autoFocusTimeoutTestDuration
         )
 
+        // simulate UseCaseCamera timing out during auto focus
+        fakeRequestControl.focusMeteringResult.complete(
+            Result3A(status = Result3A.Status.TIME_LIMIT_REACHED)
+        )
+
         // Assert.
         assertFutureFocusCompleted(future, false)
     }
 
     @Test
-    fun startFocusMetering_afAutoModeIsSet() {
+    fun startFocusMetering_afAutoModeIsSet() = runTest {
         // Arrange.
         val action = FocusMeteringAction.Builder(point1, FocusMeteringAction.FLAG_AF).build()
         val state3AControl = createState3AControl(CAMERA_ID_0)
@@ -1130,7 +1170,8 @@
         )
 
         // Act.
-        focusMeteringControl.startFocusAndMetering(
+        focusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
+            this,
             action
         )[5, TimeUnit.SECONDS]
 
@@ -1141,7 +1182,7 @@
     }
 
     @Test
-    fun startFocusMetering_AfNotInvolved_afAutoModeNotSet() {
+    fun startFocusMetering_AfNotInvolved_afAutoModeNotSet() = runTest {
         // Arrange.
         val action = FocusMeteringAction.Builder(
             point1,
@@ -1156,7 +1197,8 @@
         )
 
         // Act.
-        focusMeteringControl.startFocusAndMetering(
+        focusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
+            this,
             action
         )[5, TimeUnit.SECONDS]
 
@@ -1167,7 +1209,7 @@
     }
 
     @Test
-    fun startAndThenCancel_afAutoModeNotSet(): Unit = runBlocking {
+    fun startAndThenCancel_afAutoModeNotSet(): Unit = runTest {
         // Arrange.
         val action = FocusMeteringAction.Builder(point1, FocusMeteringAction.FLAG_AF).build()
         val state3AControl = createState3AControl(CAMERA_ID_0)
@@ -1179,19 +1221,21 @@
         )
 
         // Act.
-        focusMeteringControl.startFocusAndMetering(
-            action
+        focusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
+            this,
+            action,
         )[5, TimeUnit.SECONDS]
         focusMeteringControl.cancelFocusAndMeteringAsync().join()
 
         // Assert.
+        advanceUntilIdle()
         assertThat(
             state3AControl.preferredFocusMode
         ).isEqualTo(null)
     }
 
     @Test
-    fun startFocusMetering_submitFailed_failsWithOperationCanceledOperation() = runBlocking {
+    fun startFocusMetering_submitFailed_failsWithOperationCanceledOperation() = runTest {
         fakeRequestControl.focusMeteringResult = CompletableDeferred(
             Result3A(
                 status = Result3A.Status.SUBMIT_FAILED,
@@ -1207,7 +1251,7 @@
     }
 
     @Test
-    fun startFocusMetering_noAfPoint_futureCompletesWithFocusUnsuccessful() {
+    fun startFocusMetering_noAfPoint_futureCompletesWithFocusUnsuccessful() = runTest {
         val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_1)
         val action = FocusMeteringAction.Builder(
             point1,
@@ -1219,31 +1263,32 @@
     }
 
     @Test
-    fun startFocusMetering_frameMetadataNullWithOkStatus_futureCompletesWithFocusSuccessful() {
-        /**
-         * According to [androidx.camera.camera2.pipe.graph.Controller3A.lock3A] method
-         * documentation, if the operation is not supported by the camera device, then this method
-         * returns early with Result3A made of 'OK' status and 'null' metadata.
-         */
-        fakeRequestControl.focusMeteringResult = CompletableDeferred(
-            Result3A(
-                status = Result3A.Status.OK,
-                frameMetadata = null,
+    fun startFocusMetering_frameMetadataNullWithOkStatus_futureCompletesWithFocusSuccessful() =
+        runTest {
+            /**
+             * According to [androidx.camera.camera2.pipe.graph.Controller3A.lock3A] method
+             * documentation, if the operation is not supported by the camera device, then this
+             * method returns early with Result3A made of 'OK' status and 'null' metadata.
+             */
+            fakeRequestControl.focusMeteringResult = CompletableDeferred(
+                Result3A(
+                    status = Result3A.Status.OK,
+                    frameMetadata = null,
+                )
             )
-        )
 
-        val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_0)
-        val future = focusMeteringControl.startFocusAndMetering(
-            FocusMeteringAction.Builder(
-                point1
-            ).build()
-        )
+            val focusMeteringControl = initFocusMeteringControl(CAMERA_ID_0)
+            val future = focusMeteringControl.startFocusAndMetering(
+                FocusMeteringAction.Builder(
+                    point1
+                ).build()
+            )
 
-        assertFutureFocusCompleted(future, false)
-    }
+            assertFutureFocusCompleted(future, false)
+        }
 
     @Test
-    fun startFocusMetering_noAePoint_aeRegionsSetToDefault() {
+    fun startFocusMetering_noAePoint_aeRegionsSetToDefault() = runTest {
         startFocusMeteringAndAwait(
             FocusMeteringAction.Builder(
                 point1, FocusMeteringAction.FLAG_AF or FocusMeteringAction.FLAG_AWB
@@ -1257,7 +1302,7 @@
     }
 
     @Test
-    fun startFocusMetering_noAfPoint_afRegionsSetToDefault() {
+    fun startFocusMetering_noAfPoint_afRegionsSetToDefault() = runTest {
         startFocusMeteringAndAwait(
             FocusMeteringAction.Builder(
                 point1, FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AWB
@@ -1271,7 +1316,7 @@
     }
 
     @Test
-    fun startFocusMetering_noAwbPoint_awbRegionsSetToDefault() {
+    fun startFocusMetering_noAwbPoint_awbRegionsSetToDefault() = runTest {
         startFocusMeteringAndAwait(
             FocusMeteringAction.Builder(
                 point1, FocusMeteringAction.FLAG_AE or FocusMeteringAction.FLAG_AF
@@ -1285,7 +1330,7 @@
     }
 
     @Test
-    fun startFocusMetering_onlyAfSupported_unsupportedRegionsNotConfigured() {
+    fun startFocusMetering_onlyAfSupported_unsupportedRegionsNotConfigured() = runTest {
         // camera 5 supports 1 AF and 0 AE/AWB regions
         focusMeteringControl = initFocusMeteringControl(cameraId = CAMERA_ID_5)
 
@@ -1310,19 +1355,19 @@
         }
     }
 
-    // TODO: Port the following tests once their corresponding logics have been implemented.
-    //  - [b/255679866] triggerAfWithTemplate, triggerAePrecaptureWithTemplate,
-    //          cancelAfAeTriggerWithTemplate
-
-    private fun assertFutureFocusCompleted(
+    private fun TestScope.assertFutureFocusCompleted(
         future: ListenableFuture<FocusMeteringResult>,
         isFocused: Boolean
     ) {
+        advanceUntilIdle()
         val focusMeteringResult = future[3, TimeUnit.SECONDS]
         assertThat(focusMeteringResult.isFocusSuccessful).isEqualTo(isFocused)
     }
 
-    private fun <T> assertFutureFailedWithIllegalArgumentException(future: ListenableFuture<T>) {
+    private fun <T> TestScope.assertFutureFailedWithIllegalArgumentException(
+        future: ListenableFuture<T>
+    ) {
+        advanceUntilIdle()
         assertThrows(ExecutionException::class.java) {
             future[3, TimeUnit.SECONDS]
         }.apply {
@@ -1330,7 +1375,9 @@
         }
     }
 
-    private fun <T> assertFutureFailedWithOperationCancellation(future: ListenableFuture<T>) {
+    private fun <T> assertFutureFailedWithOperationCancellation(
+        future: ListenableFuture<T>
+    ) {
         assertThrows(ExecutionException::class.java) {
             future[3, TimeUnit.SECONDS]
         }.apply {
@@ -1338,6 +1385,13 @@
         }
     }
 
+    private fun <T> TestScope.assertFutureFailedWithOperationCancellation(
+        future: ListenableFuture<T>
+    ) {
+        advanceUntilIdle()
+        this@FocusMeteringControlTest.assertFutureFailedWithOperationCancellation(future)
+    }
+
     private val focusMeteringResultCallback = object : FutureCallback<FocusMeteringResult?> {
         private var latch = CountDownLatch(1)
 
@@ -1379,7 +1433,7 @@
         )
     }
 
-    private fun startFocusMeteringAndAwait(action: FocusMeteringAction) = runBlocking {
+    private fun startFocusMeteringAndAwait(action: FocusMeteringAction) = runTest {
         startFocusMetering(action)
         focusMeteringResultCallback.await()
     }
@@ -1567,7 +1621,7 @@
     private fun createPreview(suggestedStreamSpecResolution: Size) =
         Preview.Builder()
             .setCaptureOptionUnpacker { _, _ -> }
-            .setSessionOptionUnpacker() { _, _, _ -> }
+            .setSessionOptionUnpacker { _, _, _ -> }
             .build().apply {
                 setSurfaceProvider(
                     CameraXExecutors.mainThreadExecutor(),
@@ -1588,4 +1642,18 @@
         properties,
         useCaseCamera
     )
+
+    private fun FocusMeteringControl.startFocusAndMeteringAndAdvanceTestScope(
+        testScope: TestScope,
+        action: FocusMeteringAction,
+        autoFocusTimeoutMs: Long? = null
+    ): ListenableFuture<FocusMeteringResult> {
+        val future = autoFocusTimeoutMs?.let {
+            startFocusAndMetering(action, it)
+        } ?: run {
+            startFocusAndMetering(action)
+        }
+        testScope.advanceUntilIdle()
+        return future
+    }
 }
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 236bd7d..ab80d78 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
@@ -28,6 +28,7 @@
 import androidx.camera.camera2.pipe.AeMode
 import androidx.camera.camera2.pipe.AfMode
 import androidx.camera.camera2.pipe.AwbMode
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.Request
@@ -139,6 +140,8 @@
             afLockBehavior: Lock3ABehavior?,
             awbLockBehavior: Lock3ABehavior?,
             afTriggerStartAeMode: AeMode?,
+            convergedCondition: ((FrameMetadata) -> Boolean)?,
+            lockedCondition: ((FrameMetadata) -> Boolean)?,
             frameLimit: Int,
             timeLimitNs: Long
         ): Deferred<Result3A> {
@@ -150,6 +153,7 @@
             ae: Boolean?,
             af: Boolean?,
             awb: Boolean?,
+            unlockedCondition: ((FrameMetadata) -> Boolean)?,
             frameLimit: Int,
             timeLimitNs: Long
         ): Deferred<Result3A> {
@@ -158,6 +162,7 @@
         }
 
         override suspend fun lock3AForCapture(
+            lockedCondition: ((FrameMetadata) -> Boolean)?,
             frameLimit: Int,
             timeLimitNs: Long
         ): Deferred<Result3A> {
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
index ebc5958..806a400 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/testing/FakeCameraGraphSession.kt
@@ -23,6 +23,7 @@
 import androidx.camera.camera2.pipe.AfMode
 import androidx.camera.camera2.pipe.AwbMode
 import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.Request
@@ -73,13 +74,19 @@
         afLockBehavior: Lock3ABehavior?,
         awbLockBehavior: Lock3ABehavior?,
         afTriggerStartAeMode: AeMode?,
+        convergedCondition: ((FrameMetadata) -> Boolean)?,
+        lockedCondition: ((FrameMetadata) -> Boolean)?,
         frameLimit: Int,
         timeLimitNs: Long
     ): Deferred<Result3A> {
         throw NotImplementedError("Not used in testing")
     }
 
-    override suspend fun lock3AForCapture(frameLimit: Int, timeLimitNs: Long): Deferred<Result3A> {
+    override suspend fun lock3AForCapture(
+        lockedCondition: ((FrameMetadata) -> Boolean)?,
+        frameLimit: Int,
+        timeLimitNs: Long
+    ): Deferred<Result3A> {
         throw NotImplementedError("Not used in testing")
     }
 
@@ -127,6 +134,7 @@
         ae: Boolean?,
         af: Boolean?,
         awb: Boolean?,
+        unlockedCondition: ((FrameMetadata) -> Boolean)?,
         frameLimit: Int,
         timeLimitNs: Long
     ): Deferred<Result3A> {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
index d6a589d..f9b7c7b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/CameraGraph.kt
@@ -366,6 +366,14 @@
          *
          * @param afTriggerStartAeMode the AeMode value that should override current AeMode for
          *   AF_TRIGGER_START request, this value should not be retained for following requests
+         * @param convergedCondition an optional function can be used to identify if the result
+         * frame with correct 3A converge state is received. Returns true to complete the 3A scan
+         * and going to lock the 3A state, otherwise it will continue to receive the frame results
+         * until the [frameLimit] or [timeLimitNs] is reached.
+         * @param lockedCondition an optional function can be used to identify if the result frame
+         * with correct 3A lock states are received. Returns true to complete lock 3A task,
+         * otherwise it will continue to receive the frame results until the [frameLimit]
+         * or [timeLimitNs] is reached.
          * @param frameLimit the maximum number of frames to wait before we give up waiting for this
          *   operation to complete.
          * @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
@@ -391,6 +399,8 @@
             afLockBehavior: Lock3ABehavior? = null,
             awbLockBehavior: Lock3ABehavior? = null,
             afTriggerStartAeMode: AeMode? = null,
+            convergedCondition: ((FrameMetadata) -> Boolean)? = null,
+            lockedCondition: ((FrameMetadata) -> Boolean)? = null,
             frameLimit: Int = DEFAULT_FRAME_LIMIT,
             timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
         ): Deferred<Result3A>
@@ -405,6 +415,10 @@
          * that component, i.e. if it was locked earlier it will stay locked and if it was already
          * unlocked, it will stay unlocked.
          *
+         * @param unlockedCondition an optional function can be used to identify if the result frame
+         * with correct ae, af and awb states are received. Returns true to complete the unlock
+         * 3A task, otherwise it will continue to receive the frame results until the [frameLimit]
+         * or [timeLimitNs] is reached.
          * @param frameLimit the maximum number of frames to wait before we give up waiting for this
          *   operation to complete.
          * @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
@@ -417,6 +431,7 @@
             ae: Boolean? = null,
             af: Boolean? = null,
             awb: Boolean? = null,
+            unlockedCondition: ((FrameMetadata) -> Boolean)? = null,
             frameLimit: Int = DEFAULT_FRAME_LIMIT,
             timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
         ): Deferred<Result3A>
@@ -429,6 +444,10 @@
          * mode was set to [AeMode.ON_AUTO_FLASH] or [AeMode.ON_ALWAYS_FLASH], thus firing it for
          * low light captures or for every capture, respectively.
          *
+         * @param lockedCondition an optional function can be used to identify if the result frame
+         * with correct lock states for ae, af and awb is received. Returns true to complete lock
+         * 3A task, otherwise it will continue to receive the frame results until the [frameLimit]
+         * or [timeLimitNs] is reached.
          * @param frameLimit the maximum number of frames to wait before we give up waiting for this
          *   operation to complete.
          * @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
@@ -438,6 +457,7 @@
          *   limit or time limit was reached.
          */
         suspend fun lock3AForCapture(
+            lockedCondition: ((FrameMetadata) -> Boolean)? = null,
             frameLimit: Int = DEFAULT_FRAME_LIMIT,
             timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
         ): Deferred<Result3A>
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphSessionImpl.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphSessionImpl.kt
index e39343f..6fa5706 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphSessionImpl.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/CameraGraphSessionImpl.kt
@@ -24,6 +24,7 @@
 import androidx.camera.camera2.pipe.AfMode
 import androidx.camera.camera2.pipe.AwbMode
 import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.Request
 import androidx.camera.camera2.pipe.Result3A
@@ -124,6 +125,8 @@
         afLockBehavior: Lock3ABehavior?,
         awbLockBehavior: Lock3ABehavior?,
         afTriggerStartAeMode: AeMode?,
+        convergedCondition: ((FrameMetadata) -> Boolean)?,
+        lockedCondition: ((FrameMetadata) -> Boolean)?,
         frameLimit: Int,
         timeLimitNs: Long
     ): Deferred<Result3A> {
@@ -139,6 +142,8 @@
             afLockBehavior,
             awbLockBehavior,
             afTriggerStartAeMode,
+            convergedCondition,
+            lockedCondition,
             frameLimit,
             timeLimitNs
         )
@@ -148,16 +153,21 @@
         ae: Boolean?,
         af: Boolean?,
         awb: Boolean?,
+        unlockedCondition: ((FrameMetadata) -> Boolean)?,
         frameLimit: Int,
         timeLimitNs: Long
     ): Deferred<Result3A> {
         check(!closed.value) { "Cannot call unlock3A on $this after close." }
-        return controller3A.unlock3A(ae, af, awb, frameLimit, timeLimitNs)
+        return controller3A.unlock3A(ae, af, awb, unlockedCondition, frameLimit, timeLimitNs)
     }
 
-    override suspend fun lock3AForCapture(frameLimit: Int, timeLimitNs: Long): Deferred<Result3A> {
+    override suspend fun lock3AForCapture(
+        lockedCondition: ((FrameMetadata) -> Boolean)?,
+        frameLimit: Int,
+        timeLimitNs: Long
+    ): Deferred<Result3A> {
         check(!closed.value) { "Cannot call lock3AForCapture on $this after close." }
-        return controller3A.lock3AForCapture(frameLimit, timeLimitNs)
+        return controller3A.lock3AForCapture(lockedCondition, frameLimit, timeLimitNs)
     }
 
     override suspend fun unlock3APostCapture(): Deferred<Result3A> {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
index a8d071a..7cf11a9 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Controller3A.kt
@@ -38,6 +38,7 @@
 import androidx.camera.camera2.pipe.CameraMetadata
 import androidx.camera.camera2.pipe.CameraMetadata.Companion.supportsAutoFocusTrigger
 import androidx.camera.camera2.pipe.FlashMode
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.Result3A
 import androidx.camera.camera2.pipe.Result3A.Status
@@ -130,6 +131,26 @@
                 CaptureResult.CONTROL_AWB_STATE_SEARCHING,
                 CaptureResult.CONTROL_AWB_STATE_CONVERGED
             )
+
+        private val defaultLock3AForCaptureLockCondition = mapOf<CaptureResult.Key<*>, List<Any>>(
+            CaptureResult.CONTROL_AE_STATE to aePostPrecaptureStateList,
+            CaptureResult.CONTROL_AF_STATE to afLockedStateList
+        ).toConditionChecker()
+
+        private val unlock3APostCaptureLockAeParams =
+            mapOf(CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_CANCEL, CONTROL_AE_LOCK to true)
+
+        private val unlock3APostCaptureUnlockAeParams =
+            mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false)
+
+        private val aePrecaptureAndAfCancelParams = mapOf<CaptureRequest.Key<*>, Any>(
+            CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_CANCEL,
+            CONTROL_AE_PRECAPTURE_TRIGGER to CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
+        )
+
+        private val unlock3APostCaptureAfUnlockedCondition = mapOf<CaptureResult.Key<*>, List<Any>>(
+            CaptureResult.CONTROL_AF_STATE to afUnlockedStateList
+        ).toConditionChecker()
     }
 
     // Keep track of the result associated with latest call to update3A. If update3A is called again
@@ -247,6 +268,8 @@
         afLockBehavior: Lock3ABehavior? = null,
         awbLockBehavior: Lock3ABehavior? = null,
         afTriggerStartAeMode: AeMode? = null,
+        convergedCondition: ((FrameMetadata) -> Boolean)? = null,
+        lockedCondition: ((FrameMetadata) -> Boolean)? = null,
         frameLimit: Int = DEFAULT_FRAME_LIMIT,
         timeLimitNs: Long? = DEFAULT_TIME_LIMIT_NS
     ): Deferred<Result3A> {
@@ -283,12 +306,11 @@
             afLockBehaviorSanitized.shouldWaitForAfToConverge() ||
             awbLockBehavior.shouldWaitForAwbToConverge()
         ) {
-            val converged3AExitConditions =
-                createConverged3AExitConditions(
-                    aeLockBehavior.shouldWaitForAeToConverge(),
-                    afLockBehaviorSanitized.shouldWaitForAfToConverge(),
-                    awbLockBehavior.shouldWaitForAwbToConverge()
-                )
+            val converged3AExitConditions = convergedCondition ?: createConverged3AExitConditions(
+                aeLockBehavior.shouldWaitForAeToConverge(),
+                afLockBehaviorSanitized.shouldWaitForAfToConverge(),
+                awbLockBehavior.shouldWaitForAwbToConverge()
+            ).toConditionChecker()
             val listener =
                 Result3AStateListenerImpl(converged3AExitConditions, frameLimit, timeLimitNs)
             graphListener3A.addListener(listener)
@@ -330,6 +352,7 @@
             afLockBehaviorSanitized,
             awbLockBehavior,
             afTriggerStartAeMode,
+            lockedCondition,
             frameLimit,
             timeLimitNs
         )
@@ -347,6 +370,7 @@
         ae: Boolean? = null,
         af: Boolean? = null,
         awb: Boolean? = null,
+        unlockedCondition: ((FrameMetadata) -> Boolean)? = null,
         frameLimit: Int = DEFAULT_FRAME_LIMIT,
         timeLimitNs: Long? = DEFAULT_TIME_LIMIT_NS
     ): Deferred<Result3A> {
@@ -372,8 +396,11 @@
         }
 
         // As needed unlock ae, awb and wait for ae, af and awb to converge.
-        val unlocked3AExitConditions =
-            createUnLocked3AExitConditions(ae == true, afSanitized == true, awb == true)
+        val unlocked3AExitConditions = unlockedCondition ?: createUnLocked3AExitConditions(
+            ae == true,
+            afSanitized == true,
+            awb == true,
+        ).toConditionChecker()
         val listener = Result3AStateListenerImpl(unlocked3AExitConditions, frameLimit, timeLimitNs)
         graphListener3A.addListener(listener)
 
@@ -390,6 +417,7 @@
     }
 
     suspend fun lock3AForCapture(
+        lockedCondition: ((FrameMetadata) -> Boolean)? = null,
         frameLimit: Int = DEFAULT_FRAME_LIMIT,
         timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
     ): Deferred<Result3A> {
@@ -399,10 +427,7 @@
         }
         val listener =
             Result3AStateListenerImpl(
-                mapOf<CaptureResult.Key<*>, List<Any>>(
-                    CaptureResult.CONTROL_AE_STATE to aePostPrecaptureStateList,
-                    CaptureResult.CONTROL_AF_STATE to afLockedStateList
-                ),
+                lockedCondition ?: defaultLock3AForCaptureLockCondition,
                 frameLimit,
                 timeLimitNs
             )
@@ -441,24 +466,18 @@
      */
     private suspend fun unlock3APostCaptureAndroidLAndBelow(): Deferred<Result3A> {
         debug { "unlock3AForCapture - sending a request to cancel af and turn on ae." }
-        if (!graphProcessor.trySubmit(
-                mapOf(CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_CANCEL, CONTROL_AE_LOCK to true)
-            )
-        ) {
+        if (!graphProcessor.trySubmit(unlock3APostCaptureLockAeParams)) {
             debug { "unlock3AForCapture - request to cancel af and lock ae as failed." }
             return deferredResult3ASubmitFailed
         }
 
         // Listener to monitor when we receive the capture result corresponding to the request
         // below.
-        val listener = Result3AStateListenerImpl(mapOf())
+        val listener = Result3AStateListenerImpl(emptyMap())
         graphListener3A.addListener(listener)
 
         debug { "unlock3AForCapture - sending a request to turn off ae." }
-        if (!graphProcessor.trySubmit(
-                mapOf<CaptureRequest.Key<*>, Any>(CONTROL_AE_LOCK to false)
-            )
-        ) {
+        if (!graphProcessor.trySubmit(unlock3APostCaptureUnlockAeParams)) {
             debug { "unlock3AForCapture - request to unlock ae failed." }
             graphListener3A.removeListener(listener)
             return deferredResult3ASubmitFailed
@@ -475,13 +494,7 @@
     @RequiresApi(23)
     private suspend fun unlock3APostCaptureAndroidMAndAbove(): Deferred<Result3A> {
         debug { "unlock3APostCapture - sending a request to reset af and ae precapture metering." }
-        val parametersForAePrecaptureAndAfCancel =
-            mapOf<CaptureRequest.Key<*>, Any>(
-                CONTROL_AF_TRIGGER to CONTROL_AF_TRIGGER_CANCEL,
-                CONTROL_AE_PRECAPTURE_TRIGGER to
-                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
-            )
-        if (!graphProcessor.trySubmit(parametersForAePrecaptureAndAfCancel)) {
+        if (!graphProcessor.trySubmit(aePrecaptureAndAfCancelParams)) {
             debug {
                 "unlock3APostCapture - request to reset af and ae precapture metering failed, " +
                     "returning early."
@@ -493,12 +506,7 @@
         // on the ae state, so we don't need to listen for a specific state. As long as the request
         // successfully reaches the camera device and the capture request corresponding to that
         // request arrives back, it should suffice.
-        val listener =
-            Result3AStateListenerImpl(
-                mapOf<CaptureResult.Key<*>, List<Any>>(
-                    CaptureResult.CONTROL_AF_STATE to afUnlockedStateList
-                )
-            )
+        val listener = Result3AStateListenerImpl(unlock3APostCaptureAfUnlockedCondition)
         graphListener3A.addListener(listener)
         graphProcessor.invalidate()
         return listener.result
@@ -523,6 +531,7 @@
         afLockBehavior: Lock3ABehavior?,
         awbLockBehavior: Lock3ABehavior?,
         afTriggerStartAeMode: AeMode? = null,
+        lockedCondition: ((FrameMetadata) -> Boolean)?,
         frameLimit: Int?,
         timeLimitNs: Long?
     ): Deferred<Result3A> {
@@ -534,9 +543,10 @@
             )
 
         var resultForLocked: Deferred<Result3A>? = null
-        if (locked3AExitConditions.isNotEmpty()) {
+        if (lockedCondition != null || locked3AExitConditions.isNotEmpty()) {
+            val exitCondition = lockedCondition ?: locked3AExitConditions.toConditionChecker()
             val listener =
-                Result3AStateListenerImpl(locked3AExitConditions, frameLimit, timeLimitNs)
+                Result3AStateListenerImpl(exitCondition, frameLimit, timeLimitNs)
             graphListener3A.addListener(listener)
             graphState3A.update(aeLock = finalAeLockValue, awbLock = finalAwbLockValue)
             debug {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Result3AStateListener.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Result3AStateListener.kt
index 06dc9ee..e322564 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Result3AStateListener.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/graph/Result3AStateListener.kt
@@ -48,11 +48,21 @@
 }
 
 internal class Result3AStateListenerImpl(
-    private val exitConditionForKeys: Map<CaptureResult.Key<*>, List<Any>>,
+    private val exitCondition: (FrameMetadata) -> Boolean,
     private val frameLimit: Int? = null,
     private val timeLimitNs: Long? = null
 ) : Result3AStateListener {
 
+    internal constructor(
+        exitConditionForKeys: Map<CaptureResult.Key<*>, List<Any>>,
+        frameLimit: Int? = null,
+        timeLimitNs: Long? = null
+    ) : this(
+        exitCondition = exitConditionForKeys.toConditionChecker(),
+        frameLimit = frameLimit,
+        timeLimitNs = timeLimitNs,
+    )
+
     private val _result = CompletableDeferred<Result3A>()
     val result: Deferred<Result3A>
         get() = _result
@@ -118,11 +128,8 @@
             return true
         }
 
-        for ((k, v) in exitConditionForKeys) {
-            val valueInCaptureResult = frameMetadata[k]
-            if (!v.contains(valueInCaptureResult)) {
-                return false
-            }
+        if (!exitCondition(frameMetadata)) {
+            return false
         }
         _result.complete(Result3A(Result3A.Status.OK, frameMetadata))
         return true
@@ -136,3 +143,15 @@
         return _result
     }
 }
+
+internal fun Map<CaptureResult.Key<*>, List<Any>>.toConditionChecker(): (FrameMetadata) -> Boolean {
+    return conditionChecker@{ frameMetadata ->
+        for ((k, v) in this) {
+            val valueInCaptureResult = frameMetadata[k]
+            if (!v.contains(valueInCaptureResult)) {
+                return@conditionChecker false
+            }
+        }
+        return@conditionChecker true
+    }
+}
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AForCaptureTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AForCaptureTest.kt
index 1dd731f..95006b2 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AForCaptureTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AForCaptureTest.kt
@@ -21,6 +21,7 @@
 import android.hardware.camera2.CaptureRequest
 import android.hardware.camera2.CaptureResult
 import android.os.Build
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.RequestNumber
 import androidx.camera.camera2.pipe.Result3A
@@ -32,6 +33,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.runTest
 import org.junit.After
@@ -137,6 +139,77 @@
     }
 
     @Test
+    fun testCustomizedExitCondition_lock3AForCaptureWithoutAeState() = runTest {
+        // Arrange, prepare customized locked conditions which allow an empty AE/AF state.
+        val lockCondition: (FrameMetadata) -> Boolean = lockCondition@{ frameMetadata ->
+            val aeUnlocked = frameMetadata[CaptureResult.CONTROL_AE_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AE_STATE_CONVERGED,
+                    CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED,
+                    CaptureResult.CONTROL_AE_STATE_LOCKED
+                ).contains(it)
+            } ?: true
+
+            val afUnlocked = frameMetadata[CaptureResult.CONTROL_AF_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
+                    CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
+                ).contains(it)
+            } ?: true
+
+            return@lockCondition aeUnlocked && afUnlocked
+        }
+        val result = controller3A.lock3AForCapture(lockedCondition = lockCondition)
+        assertThat(result.isCompleted).isFalse()
+
+        // Simulate repeatedly invoke the scanning state.
+        val repeatingJob = async {
+            var frameNumber = 100L
+            while (frameNumber < 110L) {
+                listener3A.onRequestSequenceCreated(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1))
+                )
+                listener3A.onPartialCaptureResult(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1)),
+                    FrameNumber(frameNumber),
+                    FakeFrameMetadata(
+                        frameNumber = FrameNumber(frameNumber++),
+                        resultMetadata =
+                        mapOf(
+                            CaptureResult.CONTROL_AF_STATE to
+                                CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
+                        )
+                    )
+                )
+                delay(FRAME_RATE_MS)
+            }
+        }
+        repeatingJob.await()
+        assertThat(result.isCompleted).isFalse()
+
+        // Act, simulate the locked result without AE state.
+        listener3A.onRequestSequenceCreated(
+            FakeRequestMetadata(requestNumber = RequestNumber(1))
+        )
+        listener3A.onPartialCaptureResult(
+            FakeRequestMetadata(requestNumber = RequestNumber(1)),
+            FrameNumber(120L),
+            FakeFrameMetadata(
+                frameNumber = FrameNumber(120L),
+                resultMetadata =
+                mapOf(
+                    CaptureResult.CONTROL_AF_STATE to
+                        CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
+                )
+            )
+        )
+
+        // Assert, task should be completed with Status.Ok
+        val result3A = result.await()
+        assertThat(result3A.status).isEqualTo(Result3A.Status.OK)
+    }
+
+    @Test
     fun testUnlock3APostCapture() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             testUnlock3APostCaptureAndroidMAndAbove()
@@ -241,4 +314,9 @@
         val request2 = captureSequenceProcessor.nextEvent().requestSequence
         assertThat(request2!!.requiredParameters[CaptureRequest.CONTROL_AE_LOCK]).isEqualTo(false)
     }
+
+    companion object {
+        // The time duration in milliseconds between two frame results.
+        private const val FRAME_RATE_MS = 33L
+    }
 }
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3ALock3ATest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3ALock3ATest.kt
index 4b049be..3c43c5c 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3ALock3ATest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3ALock3ATest.kt
@@ -21,6 +21,7 @@
 import android.hardware.camera2.CaptureResult
 import android.hardware.camera2.params.MeteringRectangle
 import android.os.Build
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.Lock3ABehavior
 import androidx.camera.camera2.pipe.RequestNumber
@@ -753,6 +754,117 @@
         assertThat(result.frameMetadata).isEqualTo(null)
     }
 
+    @Test
+    fun testCustomizedExitConditionForEmptyAeState_newScanLock3A() = runTest {
+        // Arrange, set up exit conditions which allow 3A state to be empty.
+        val convergeCondition: (FrameMetadata) -> Boolean = convergeCondition@{ frameMetadata ->
+            val aeUnlocked = frameMetadata[CaptureResult.CONTROL_AE_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AE_STATE_CONVERGED,
+                    CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED,
+                    CaptureResult.CONTROL_AE_STATE_LOCKED
+                ).contains(it)
+            } ?: true
+
+            val afUnlocked = frameMetadata[CaptureResult.CONTROL_AF_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED,
+                    CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED,
+                    CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
+                    CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
+                ).contains(it)
+            } ?: true
+
+            val awbUnlocked = frameMetadata[CaptureResult.CONTROL_AWB_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AWB_STATE_CONVERGED,
+                    CaptureResult.CONTROL_AWB_STATE_LOCKED
+                ).contains(it)
+            } ?: true
+
+            return@convergeCondition aeUnlocked && afUnlocked && awbUnlocked
+        }
+        val lockCondition: (FrameMetadata) -> Boolean = lockCondition@{ frameMetadata ->
+            val aeUnlocked = frameMetadata[CaptureResult.CONTROL_AE_STATE]?.let {
+                listOf(CaptureResult.CONTROL_AE_STATE_LOCKED).contains(it)
+            } ?: true
+
+            val afUnlocked = frameMetadata[CaptureResult.CONTROL_AF_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
+                    CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
+                ).contains(it)
+            } ?: true
+
+            val awbUnlocked = frameMetadata[CaptureResult.CONTROL_AWB_STATE]?.let {
+                listOf(CaptureResult.CONTROL_AWB_STATE_LOCKED).contains(it)
+            } ?: true
+
+            return@lockCondition aeUnlocked && afUnlocked && awbUnlocked
+        }
+
+        // Act. lock3A with new scan
+        val lock3AAsyncTask = async {
+            controller3A.lock3A(
+                afLockBehavior = Lock3ABehavior.AFTER_NEW_SCAN,
+                aeLockBehavior = Lock3ABehavior.AFTER_NEW_SCAN,
+                awbLockBehavior = Lock3ABehavior.AFTER_NEW_SCAN,
+                convergedCondition = convergeCondition,
+                lockedCondition = lockCondition,
+            )
+        }
+
+        // Simulate repeatedly invoke without AE state.
+        val repeatingJob = async {
+            var frameNumber = 101L
+            while (frameNumber < 110L) {
+                listener3A.onRequestSequenceCreated(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1))
+                )
+                listener3A.onPartialCaptureResult(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1)),
+                    FrameNumber(frameNumber),
+                    FakeFrameMetadata(
+                        frameNumber = FrameNumber(frameNumber++),
+                        resultMetadata = mapOf(
+                            CaptureResult.CONTROL_AF_STATE to
+                                CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED,
+                            CaptureResult.CONTROL_AWB_STATE to
+                                CaptureResult.CONTROL_AWB_STATE_CONVERGED
+                        )
+                    )
+                )
+                delay(FRAME_RATE_MS)
+            }
+        }
+        val deferredResult = lock3AAsyncTask.await()
+        repeatingJob.await()
+        assertThat(deferredResult.isCompleted).isFalse()
+
+        // Simulate locked AF, AWB invoke without AE locked info.
+        listener3A.onRequestSequenceCreated(
+            FakeRequestMetadata(requestNumber = RequestNumber(1))
+        )
+        listener3A.onPartialCaptureResult(
+            FakeRequestMetadata(requestNumber = RequestNumber(1)),
+            FrameNumber(120L),
+            FakeFrameMetadata(
+                frameNumber = FrameNumber(120L),
+                resultMetadata =
+                mapOf(
+                    CaptureResult.CONTROL_AF_STATE to
+                        CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
+                    CaptureResult.CONTROL_AWB_STATE to
+                        CaptureResult.CONTROL_AWB_STATE_LOCKED
+                )
+            )
+        )
+
+        // Assert. lock3A task should be completed.
+        val result3A = deferredResult.await()
+        assertThat(result3A.status).isEqualTo(Result3A.Status.OK)
+    }
+
     companion object {
         // The time duration in milliseconds between two frame results.
         private const val FRAME_RATE_MS = 33L
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AUnlock3ATest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AUnlock3ATest.kt
index 69dafc1..61dcca8 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AUnlock3ATest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Controller3AUnlock3ATest.kt
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CaptureRequest
 import android.hardware.camera2.CaptureResult
 import android.os.Build
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.RequestNumber
 import androidx.camera.camera2.pipe.Result3A
@@ -376,6 +377,77 @@
         repeatingJob.join()
     }
 
+    @Test
+    fun testUnlockWithCustomizedExitCondition() = runTest {
+        // Arrange. Launch a task to repeatedly invoke without AE state info.
+        val repeatingJob = async {
+            var frameNumber = 101L
+            while (frameNumber < 110L) {
+                listener3A.onRequestSequenceCreated(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1))
+                )
+                listener3A.onPartialCaptureResult(
+                    FakeRequestMetadata(requestNumber = RequestNumber(1)),
+                    FrameNumber(frameNumber),
+                    FakeFrameMetadata(
+                        frameNumber = FrameNumber(frameNumber++),
+                        resultMetadata = mapOf(
+                            CaptureResult.CONTROL_AF_STATE to
+                                CaptureResult.CONTROL_AF_STATE_INACTIVE,
+                            CaptureResult.CONTROL_AWB_STATE to
+                                CaptureResult.CONTROL_AWB_STATE_INACTIVE,
+                        )
+                    )
+                )
+                delay(FRAME_RATE_MS)
+            }
+        }
+
+        val customizedExitCondition: (FrameMetadata) -> Boolean = exitCondition@{ frameMetadata ->
+            val aeUnlocked = frameMetadata[CaptureResult.CONTROL_AE_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AE_STATE_INACTIVE,
+                    CaptureResult.CONTROL_AE_STATE_SEARCHING,
+                    CaptureResult.CONTROL_AE_STATE_CONVERGED,
+                    CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
+                ).contains(it)
+            } ?: true
+
+            val afUnlocked = frameMetadata[CaptureResult.CONTROL_AF_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AF_STATE_INACTIVE,
+                    CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN,
+                    CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
+                    CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED,
+                    CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED
+                ).contains(it)
+            } ?: true
+
+            val awbUnlocked = frameMetadata[CaptureResult.CONTROL_AWB_STATE]?.let {
+                listOf(
+                    CaptureResult.CONTROL_AWB_STATE_INACTIVE,
+                    CaptureResult.CONTROL_AWB_STATE_SEARCHING,
+                    CaptureResult.CONTROL_AWB_STATE_CONVERGED
+                ).contains(it)
+            } ?: true
+
+            return@exitCondition aeUnlocked && afUnlocked && awbUnlocked
+        }
+
+        // Act. Unlock AE
+        val result3ADeferred = controller3A.unlock3A(
+            ae = true,
+            af = true,
+            awb = true,
+            unlockedCondition = customizedExitCondition,
+        )
+        repeatingJob.await()
+
+        // Assert. Result of unlock3A call should be completed.
+        assertThat(result3ADeferred.isCompleted).isTrue()
+        assertThat(result3ADeferred.getCompleted().status).isEqualTo(Result3A.Status.OK)
+    }
+
     companion object {
         // The time duration in milliseconds between two frame results.
         private const val FRAME_RATE_MS = 33L
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Result3AStateListenerImplTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Result3AStateListenerImplTest.kt
index e6519a8..8342191 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Result3AStateListenerImplTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/graph/Result3AStateListenerImplTest.kt
@@ -18,6 +18,7 @@
 
 import android.hardware.camera2.CaptureResult
 import android.os.Build
+import androidx.camera.camera2.pipe.FrameMetadata
 import androidx.camera.camera2.pipe.FrameNumber
 import androidx.camera.camera2.pipe.RequestNumber
 import androidx.camera.camera2.pipe.Result3A
@@ -394,4 +395,46 @@
         listenerForKeys.update(RequestNumber(3), frameMetadata)
         assertThat(listenerForKeys.result.isCompleted).isTrue()
     }
+
+    @Test
+    fun testExitFunctionWithDesiredValue() {
+        val exitCondition: (FrameMetadata) -> Boolean = { frameMetadata ->
+            frameMetadata[CaptureResult.CONTROL_AF_STATE] ==
+                CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
+        }
+
+        val listenerForKeys = Result3AStateListenerImpl(exitCondition)
+        listenerForKeys.onRequestSequenceCreated(RequestNumber(1))
+        val frameMetadata = FakeFrameMetadata(
+            resultMetadata = mapOf(
+                CaptureResult.CONTROL_AF_STATE to
+                    CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
+            )
+        )
+        listenerForKeys.update(RequestNumber(1), frameMetadata)
+
+        // Assert. Task is completed when receiving the desired value in the FrameMetadata.
+        assertThat(listenerForKeys.result.isCompleted).isTrue()
+    }
+
+    @Test
+    fun testExitFunctionWithUndesirableValue() {
+        val exitCondition: (FrameMetadata) -> Boolean = { frameMetadata ->
+            frameMetadata[CaptureResult.CONTROL_AF_STATE] ==
+                CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
+        }
+
+        val listenerForKeys = Result3AStateListenerImpl(exitCondition)
+        listenerForKeys.onRequestSequenceCreated(RequestNumber(1))
+        val frameMetadata = FakeFrameMetadata(
+            resultMetadata = mapOf(
+                CaptureResult.CONTROL_AF_STATE to
+                    CaptureResult.CONTROL_AF_STATE_INACTIVE
+            )
+        )
+        listenerForKeys.update(RequestNumber(1), frameMetadata)
+
+        // Assert. Task is completed when receiving the desired value in the FrameMetadata.
+        assertThat(listenerForKeys.result.isCompleted).isFalse()
+    }
 }
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
index cee3266..a5a3f91 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/FocusMeteringControlTest.kt
@@ -53,8 +53,9 @@
 import java.util.concurrent.ExecutionException
 import java.util.concurrent.TimeUnit
 import junit.framework.TestCase
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertThrows
 import org.junit.Before
 import org.junit.Test
@@ -102,6 +103,7 @@
 
 private val PREVIEW_ASPECT_RATIO_4_X_3 = Rational(4, 3)
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(ParameterizedRobolectricTestRunner::class)
 @DoNotInstrument
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
@@ -644,7 +646,7 @@
     @MediumTest
     @Test
     fun shorterAutoCancelDuration_cancelIsCalled_completeActionFutureIsNotCalled(): Unit =
-        runBlocking {
+        runTest {
             focusMeteringControl = spy(focusMeteringControl)
             val autoCancelDuration: Long = 500
             val action = FocusMeteringAction.Builder(point1)
@@ -685,7 +687,7 @@
 
     @MediumTest
     @Test
-    fun autoCancelDurationDisabled_completeAfterAutoFocusTimeoutDuration(): Unit = runBlocking {
+    fun autoCancelDurationDisabled_completeAfterAutoFocusTimeoutDuration(): Unit = runTest {
         focusMeteringControl = spy(focusMeteringControl)
         val autoCancelDuration: Long = 500
         val action = FocusMeteringAction.Builder(point1)
@@ -1203,7 +1205,7 @@
 
     @MediumTest
     @Test
-    fun cancelFocusAndMetering_autoCancelIsDisabled(): Unit = runBlocking {
+    fun cancelFocusAndMetering_autoCancelIsDisabled(): Unit = runTest {
         focusMeteringControl = spy(focusMeteringControl)
         val autoCancelDuration: Long = 500
         val action = FocusMeteringAction.Builder(point1)
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 6368731..38faf0c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -50,7 +50,6 @@
 import static java.util.Collections.singletonList;
 import static java.util.Objects.requireNonNull;
 
-import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.media.ImageReader;
@@ -233,7 +232,7 @@
                 PREVIEW,
                 INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
                 streamSpec,
-                new Matrix(),
+                getSensorToBufferTransformMatrix(),
                 camera.getHasTransform(),
                 requireNonNull(getCropRect(streamSpec.getResolution())),
                 getRelativeRotation(camera, isMirroringRequired(camera)),
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index a20c1a5..26333fb 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -17,6 +17,7 @@
 package androidx.camera.core
 
 import android.content.Context
+import android.graphics.Matrix
 import android.graphics.Rect
 import android.graphics.SurfaceTexture
 import android.os.Build
@@ -101,6 +102,10 @@
 
     private val handlersToRelease = mutableListOf<Handler>()
 
+    private val sensorToBufferTransform = Matrix().apply {
+        setScale(1f, 2f)
+    }
+
     private val testImplementationOption: androidx.camera.core.impl.Config.Option<Int> =
         androidx.camera.core.impl.Config.Option.create(
             "test.testOption",
@@ -339,6 +344,7 @@
 
         // Get pending SurfaceRequest created by pipeline.
         assertThat(transformationInfo!!.hasCameraTransform()).isTrue()
+        assertThat(transformationInfo!!.sensorToBufferTransform).isEqualTo(sensorToBufferTransform)
     }
 
     @Test
@@ -791,6 +797,7 @@
         streamSpecOptions.insertOption(testImplementationOption, testImplementationOptionValue)
         val streamSpec = StreamSpec.builder(Size(640, 480))
             .setImplementationOptions(streamSpecOptions).build()
+        previewToDetach.sensorToBufferTransformMatrix = sensorToBufferTransform
         previewToDetach.updateSuggestedStreamSpec(streamSpec)
         return previewToDetach
     }
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
index f3a193e..0896f12 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
@@ -44,7 +44,6 @@
 import org.junit.After
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -156,7 +155,6 @@
             get() = ExtensionsTestUtil.getAllExtensionsLensFacingCombinations()
     }
 
-    @Ignore("b/265988873")
     @UiThreadTest
     @Test
     fun canBindToLifeCycleAndDisplayPreview(): Unit = runBlocking {
diff --git a/camera/camera-video/build.gradle b/camera/camera-video/build.gradle
index 7451fce..a617cd6f 100644
--- a/camera/camera-video/build.gradle
+++ b/camera/camera-video/build.gradle
@@ -64,7 +64,6 @@
         // Ensure camera-testing does not pull in androidx.test dependencies
         exclude(group:"androidx.test")
     }
-    android
     androidTestImplementation(libs.kotlinStdlib)
     androidTestImplementation(libs.kotlinCoroutinesAndroid)
     androidTestImplementation(project(":concurrent:concurrent-futures-ktx"))
diff --git a/camera/camera-view/build.gradle b/camera/camera-view/build.gradle
index fe5c7d2..15b4c24 100644
--- a/camera/camera-view/build.gradle
+++ b/camera/camera-view/build.gradle
@@ -64,7 +64,6 @@
         // Ensure camera-testing does not pull in androidx.test dependencies
         exclude(group:"androidx.test")
     }
-    android
     androidTestImplementation(project(":camera:camera-camera2-pipe-integration"))
     androidTestImplementation(project(":internal-testutils-truth"))
     androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it's own MockMaker
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
index 886fd7a..2bae848 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
@@ -74,7 +74,7 @@
 
 private val BACK_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 private const val BACK_LENS_FACING = CameraSelector.LENS_FACING_BACK
-private const val CAPTURE_TIMEOUT = 10_000.toLong() //  10 seconds
+private const val CAPTURE_TIMEOUT = 15_000.toLong() //  15 seconds
 
 @LargeTest
 @RunWith(Parameterized::class)
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index c9c7199..67a1fec 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -110,7 +110,7 @@
 private val BACK_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 private val FRONT_SELECTOR = CameraSelector.DEFAULT_FRONT_CAMERA
 private const val BACK_LENS_FACING = CameraSelector.LENS_FACING_BACK
-private const val CAPTURE_TIMEOUT = 10_000.toLong() //  10 seconds
+private const val CAPTURE_TIMEOUT = 15_000.toLong() //  15 seconds
 
 @LargeTest
 @RunWith(Parameterized::class)
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureWithoutStoragePermissionTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureWithoutStoragePermissionTest.kt
index 5aa7162..46313b0 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureWithoutStoragePermissionTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureWithoutStoragePermissionTest.kt
@@ -52,7 +52,7 @@
 
 private val BACK_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 private const val BACK_LENS_FACING = CameraSelector.LENS_FACING_BACK
-private const val CAPTURE_TIMEOUT = 10_000.toLong() //  10 seconds
+private const val CAPTURE_TIMEOUT = 15_000.toLong() //  15 seconds
 
 @LargeTest
 @RunWith(Parameterized::class)
@@ -196,4 +196,4 @@
             deferredItems.forEach { it.await() }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
index ff115e9..3f8535c 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
@@ -312,7 +312,7 @@
 internal val CoroutineContext.durationScale: Float
     get() {
         val scale = this[MotionDurationScale]?.scaleFactor ?: 1f
-        check(scale >= 0f)
+        check(scale >= 0f) { "negative scale factor" }
         return scale
     }
 
diff --git a/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt b/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
index c38b355..483a690 100644
--- a/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
+++ b/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
@@ -491,65 +491,67 @@
     return start.zip(stop) { a, b -> lerp(a, b, fraction) }
 }
 
+private const val DifferentStartAndStopPathNodes = "start and stop path nodes have different types"
+
 /**
  * Linearly interpolate between [start] and [stop] with [fraction] fraction between them.
  */
 private fun lerp(start: PathNode, stop: PathNode, fraction: Float): PathNode {
     return when (start) {
         is PathNode.RelativeMoveTo -> {
-            require(stop is PathNode.RelativeMoveTo)
+            require(stop is PathNode.RelativeMoveTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeMoveTo(
                 lerp(start.dx, stop.dx, fraction),
                 lerp(start.dy, stop.dy, fraction)
             )
         }
         is PathNode.MoveTo -> {
-            require(stop is PathNode.MoveTo)
+            require(stop is PathNode.MoveTo) { DifferentStartAndStopPathNodes }
             PathNode.MoveTo(
                 lerp(start.x, stop.x, fraction),
                 lerp(start.y, stop.y, fraction)
             )
         }
         is PathNode.RelativeLineTo -> {
-            require(stop is PathNode.RelativeLineTo)
+            require(stop is PathNode.RelativeLineTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeLineTo(
                 lerp(start.dx, stop.dx, fraction),
                 lerp(start.dy, stop.dy, fraction)
             )
         }
         is PathNode.LineTo -> {
-            require(stop is PathNode.LineTo)
+            require(stop is PathNode.LineTo) { DifferentStartAndStopPathNodes }
             PathNode.LineTo(
                 lerp(start.x, stop.x, fraction),
                 lerp(start.y, stop.y, fraction)
             )
         }
         is PathNode.RelativeHorizontalTo -> {
-            require(stop is PathNode.RelativeHorizontalTo)
+            require(stop is PathNode.RelativeHorizontalTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeHorizontalTo(
                 lerp(start.dx, stop.dx, fraction)
             )
         }
         is PathNode.HorizontalTo -> {
-            require(stop is PathNode.HorizontalTo)
+            require(stop is PathNode.HorizontalTo) { DifferentStartAndStopPathNodes }
             PathNode.HorizontalTo(
                 lerp(start.x, stop.x, fraction)
             )
         }
         is PathNode.RelativeVerticalTo -> {
-            require(stop is PathNode.RelativeVerticalTo)
+            require(stop is PathNode.RelativeVerticalTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeVerticalTo(
                 lerp(start.dy, stop.dy, fraction)
             )
         }
         is PathNode.VerticalTo -> {
-            require(stop is PathNode.VerticalTo)
+            require(stop is PathNode.VerticalTo) { DifferentStartAndStopPathNodes }
             PathNode.VerticalTo(
                 lerp(start.y, stop.y, fraction)
             )
         }
         is PathNode.RelativeCurveTo -> {
-            require(stop is PathNode.RelativeCurveTo)
+            require(stop is PathNode.RelativeCurveTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeCurveTo(
                 lerp(start.dx1, stop.dx1, fraction),
                 lerp(start.dy1, stop.dy1, fraction),
@@ -560,7 +562,7 @@
             )
         }
         is PathNode.CurveTo -> {
-            require(stop is PathNode.CurveTo)
+            require(stop is PathNode.CurveTo) { DifferentStartAndStopPathNodes }
             PathNode.CurveTo(
                 lerp(start.x1, stop.x1, fraction),
                 lerp(start.y1, stop.y1, fraction),
@@ -571,7 +573,7 @@
             )
         }
         is PathNode.RelativeReflectiveCurveTo -> {
-            require(stop is PathNode.RelativeReflectiveCurveTo)
+            require(stop is PathNode.RelativeReflectiveCurveTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeReflectiveCurveTo(
                 lerp(start.dx1, stop.dx1, fraction),
                 lerp(start.dy1, stop.dy1, fraction),
@@ -580,7 +582,7 @@
             )
         }
         is PathNode.ReflectiveCurveTo -> {
-            require(stop is PathNode.ReflectiveCurveTo)
+            require(stop is PathNode.ReflectiveCurveTo) { DifferentStartAndStopPathNodes }
             PathNode.ReflectiveCurveTo(
                 lerp(start.x1, stop.x1, fraction),
                 lerp(start.y1, stop.y1, fraction),
@@ -589,7 +591,7 @@
             )
         }
         is PathNode.RelativeQuadTo -> {
-            require(stop is PathNode.RelativeQuadTo)
+            require(stop is PathNode.RelativeQuadTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeQuadTo(
                 lerp(start.dx1, stop.dx1, fraction),
                 lerp(start.dy1, stop.dy1, fraction),
@@ -598,7 +600,7 @@
             )
         }
         is PathNode.QuadTo -> {
-            require(stop is PathNode.QuadTo)
+            require(stop is PathNode.QuadTo) { DifferentStartAndStopPathNodes }
             PathNode.QuadTo(
                 lerp(start.x1, stop.x1, fraction),
                 lerp(start.y1, stop.y1, fraction),
@@ -607,21 +609,21 @@
             )
         }
         is PathNode.RelativeReflectiveQuadTo -> {
-            require(stop is PathNode.RelativeReflectiveQuadTo)
+            require(stop is PathNode.RelativeReflectiveQuadTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeReflectiveQuadTo(
                 lerp(start.dx, stop.dx, fraction),
                 lerp(start.dy, stop.dy, fraction)
             )
         }
         is PathNode.ReflectiveQuadTo -> {
-            require(stop is PathNode.ReflectiveQuadTo)
+            require(stop is PathNode.ReflectiveQuadTo) { DifferentStartAndStopPathNodes }
             PathNode.ReflectiveQuadTo(
                 lerp(start.x, stop.x, fraction),
                 lerp(start.y, stop.y, fraction)
             )
         }
         is PathNode.RelativeArcTo -> {
-            require(stop is PathNode.RelativeArcTo)
+            require(stop is PathNode.RelativeArcTo) { DifferentStartAndStopPathNodes }
             PathNode.RelativeArcTo(
                 lerp(start.horizontalEllipseRadius, stop.horizontalEllipseRadius, fraction),
                 lerp(start.verticalEllipseRadius, stop.verticalEllipseRadius, fraction),
@@ -633,7 +635,7 @@
             )
         }
         is PathNode.ArcTo -> {
-            require(stop is PathNode.ArcTo)
+            require(stop is PathNode.ArcTo) { DifferentStartAndStopPathNodes }
             PathNode.ArcTo(
                 lerp(start.horizontalEllipseRadius, stop.horizontalEllipseRadius, fraction),
                 lerp(start.verticalEllipseRadius, stop.verticalEllipseRadius, fraction),
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 24143b5..162ab60 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -162,6 +162,7 @@
     ctor public MutatorMutex();
     method public suspend <R> Object? mutate(optional androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
     method public suspend <T, R> Object? mutateWith(T receiver, optional androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
+    method public inline boolean tryMutate(kotlin.jvm.functions.Function0<kotlin.Unit> block);
   }
 
   @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class OverscrollConfiguration {
@@ -234,6 +235,49 @@
 
 package androidx.compose.foundation.gestures {
 
+  @androidx.compose.foundation.ExperimentalFoundationApi public interface AnchoredDragScope {
+    method public void dragTo(float newOffset, optional float lastKnownVelocity);
+  }
+
+  public final class AnchoredDraggableKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static <T> androidx.compose.foundation.gestures.DraggableAnchors<T> DraggableAnchors(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.gestures.DraggableAnchorsConfig<T>,kotlin.Unit> builder);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static <T> androidx.compose.ui.Modifier anchoredDraggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.AnchoredDraggableState<T> state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend <T> Object? animateTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, optional float velocity, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend <T> Object? snapTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class AnchoredDraggableState<T> {
+    ctor @androidx.compose.foundation.ExperimentalFoundationApi public AnchoredDraggableState(T initialValue, androidx.compose.foundation.gestures.DraggableAnchors<T> anchors, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+    ctor public AnchoredDraggableState(T initialValue, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+    method public suspend Object? anchoredDrag(optional androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.gestures.AnchoredDragScope,? super androidx.compose.foundation.gestures.DraggableAnchors<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? anchoredDrag(T targetValue, optional androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function4<? super androidx.compose.foundation.gestures.AnchoredDragScope,? super androidx.compose.foundation.gestures.DraggableAnchors<T>,? super T,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public float dispatchRawDelta(float delta);
+    method public androidx.compose.foundation.gestures.DraggableAnchors<T> getAnchors();
+    method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getAnimationSpec();
+    method public T getCurrentValue();
+    method public float getLastVelocity();
+    method public float getOffset();
+    method public float getProgress();
+    method public T getTargetValue();
+    method public boolean isAnimationRunning();
+    method public float requireOffset();
+    method public suspend Object? settle(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void updateAnchors(androidx.compose.foundation.gestures.DraggableAnchors<T> newAnchors, optional T newTarget);
+    property public final androidx.compose.foundation.gestures.DraggableAnchors<T> anchors;
+    property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec;
+    property public final T currentValue;
+    property public final boolean isAnimationRunning;
+    property public final float lastVelocity;
+    property public final float offset;
+    property public final float progress;
+    property public final T targetValue;
+    field public static final androidx.compose.foundation.gestures.AnchoredDraggableState.Companion Companion;
+  }
+
+  public static final class AnchoredDraggableState.Companion {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.gestures.AnchoredDraggableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+  }
+
   @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public interface BringIntoViewScroller {
     method public float calculateScrollDistance(float offset, float size, float containerSize);
     method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getScrollAnimationSpec();
@@ -267,6 +311,22 @@
     method public void dragBy(float pixels);
   }
 
+  @androidx.compose.foundation.ExperimentalFoundationApi public interface DraggableAnchors<T> {
+    method public T? closestAnchor(float position);
+    method public T? closestAnchor(float position, boolean searchUpwards);
+    method public int getSize();
+    method public boolean hasAnchorFor(T value);
+    method public float maxAnchor();
+    method public float minAnchor();
+    method public float positionOf(T value);
+    property public abstract int size;
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi public final class DraggableAnchorsConfig<T> {
+    ctor public DraggableAnchorsConfig();
+    method public infix void at(T, float position);
+  }
+
   public final class DraggableKt {
     method public static androidx.compose.foundation.gestures.DraggableState DraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
     method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 2a07dc7..004920e 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -162,6 +162,9 @@
     ctor public MutatorMutex();
     method public suspend <R> Object? mutate(optional androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function1<? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
     method public suspend <T, R> Object? mutateWith(T receiver, optional androidx.compose.foundation.MutatePriority priority, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super R>,?> block, kotlin.coroutines.Continuation<? super R>);
+    method @kotlin.PublishedApi internal boolean tryLock();
+    method public inline boolean tryMutate(kotlin.jvm.functions.Function0<kotlin.Unit> block);
+    method @kotlin.PublishedApi internal void unlock();
   }
 
   @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class OverscrollConfiguration {
@@ -234,6 +237,49 @@
 
 package androidx.compose.foundation.gestures {
 
+  @androidx.compose.foundation.ExperimentalFoundationApi public interface AnchoredDragScope {
+    method public void dragTo(float newOffset, optional float lastKnownVelocity);
+  }
+
+  public final class AnchoredDraggableKt {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static <T> androidx.compose.foundation.gestures.DraggableAnchors<T> DraggableAnchors(kotlin.jvm.functions.Function1<? super androidx.compose.foundation.gestures.DraggableAnchorsConfig<T>,kotlin.Unit> builder);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static <T> androidx.compose.ui.Modifier anchoredDraggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.AnchoredDraggableState<T> state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend <T> Object? animateTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, optional float velocity, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static suspend <T> Object? snapTo(androidx.compose.foundation.gestures.AnchoredDraggableState<T>, T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public final class AnchoredDraggableState<T> {
+    ctor @androidx.compose.foundation.ExperimentalFoundationApi public AnchoredDraggableState(T initialValue, androidx.compose.foundation.gestures.DraggableAnchors<T> anchors, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+    ctor public AnchoredDraggableState(T initialValue, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+    method public suspend Object? anchoredDrag(optional androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.gestures.AnchoredDragScope,? super androidx.compose.foundation.gestures.DraggableAnchors<T>,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public suspend Object? anchoredDrag(T targetValue, optional androidx.compose.foundation.MutatePriority dragPriority, kotlin.jvm.functions.Function4<? super androidx.compose.foundation.gestures.AnchoredDragScope,? super androidx.compose.foundation.gestures.DraggableAnchors<T>,? super T,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public float dispatchRawDelta(float delta);
+    method public androidx.compose.foundation.gestures.DraggableAnchors<T> getAnchors();
+    method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getAnimationSpec();
+    method public T getCurrentValue();
+    method public float getLastVelocity();
+    method public float getOffset();
+    method public float getProgress();
+    method public T getTargetValue();
+    method public boolean isAnimationRunning();
+    method public float requireOffset();
+    method public suspend Object? settle(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method public void updateAnchors(androidx.compose.foundation.gestures.DraggableAnchors<T> newAnchors, optional T newTarget);
+    property public final androidx.compose.foundation.gestures.DraggableAnchors<T> anchors;
+    property public final androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec;
+    property public final T currentValue;
+    property public final boolean isAnimationRunning;
+    property public final float lastVelocity;
+    property public final float offset;
+    property public final float progress;
+    property public final T targetValue;
+    field public static final androidx.compose.foundation.gestures.AnchoredDraggableState.Companion Companion;
+  }
+
+  public static final class AnchoredDraggableState.Companion {
+    method @androidx.compose.foundation.ExperimentalFoundationApi public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.foundation.gestures.AnchoredDraggableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Float> positionalThreshold, kotlin.jvm.functions.Function0<java.lang.Float> velocityThreshold, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmValueChange);
+  }
+
   @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public interface BringIntoViewScroller {
     method public float calculateScrollDistance(float offset, float size, float containerSize);
     method public androidx.compose.animation.core.AnimationSpec<java.lang.Float> getScrollAnimationSpec();
@@ -267,6 +313,22 @@
     method public void dragBy(float pixels);
   }
 
+  @androidx.compose.foundation.ExperimentalFoundationApi public interface DraggableAnchors<T> {
+    method public T? closestAnchor(float position);
+    method public T? closestAnchor(float position, boolean searchUpwards);
+    method public int getSize();
+    method public boolean hasAnchorFor(T value);
+    method public float maxAnchor();
+    method public float minAnchor();
+    method public float positionOf(T value);
+    property public abstract int size;
+  }
+
+  @androidx.compose.foundation.ExperimentalFoundationApi public final class DraggableAnchorsConfig<T> {
+    ctor public DraggableAnchorsConfig();
+    method public infix void at(T, float position);
+  }
+
   public final class DraggableKt {
     method public static androidx.compose.foundation.gestures.DraggableState DraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
     method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/AnchoredDraggableDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/AnchoredDraggableDemo.kt
new file mode 100644
index 0000000..cbf4991
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/AnchoredDraggableDemo.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.demos
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.samples.AnchoredDraggableAnchorsFromCompositionSample
+import androidx.compose.foundation.samples.AnchoredDraggableCustomAnchoredSample
+import androidx.compose.foundation.samples.AnchoredDraggableLayoutDependentAnchorsSample
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+
+@Preview
+@Composable
+fun AnchoredDraggableDemo() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        AnchoredDraggableAnchorsFromCompositionSample()
+        Spacer(Modifier.height(50.dp))
+        AnchoredDraggableLayoutDependentAnchorsSample()
+        Spacer(Modifier.height(50.dp))
+        AnchoredDraggableCustomAnchoredSample()
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
index 0f8a1de..971cc2b 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
@@ -46,10 +46,15 @@
     ComposableDemo("Focus Group") { FocusGroupDemo() },
 )
 
+private val GestureDemos = listOf(
+    ComposableDemo("AnchoredDraggable") { AnchoredDraggableDemo() },
+    ComposableDemo("Draggable, Scrollable, Zoomable, Focusable") { HighLevelGesturesDemo() }
+)
+
 val FoundationDemos = DemoCategory(
     "Foundation",
     listOf(
-        ComposableDemo("Draggable, Scrollable, Zoomable, Focusable") { HighLevelGesturesDemo() },
+        DemoCategory("High-level Gesures", GestureDemos),
         ComposableDemo("Overscroll") { OverscrollDemo() },
         ComposableDemo("Can scroll forward / backward") { CanScrollSample() },
         ComposableDemo("Vertical scroll") { VerticalScrollExample() },
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/PlatformTextInputAdapterDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/PlatformTextInputAdapterDemo.kt
index 778644a..25b620f 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/PlatformTextInputAdapterDemo.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/PlatformTextInputAdapterDemo.kt
@@ -192,7 +192,7 @@
     override fun createInputConnection(outAttrs: EditorInfo): InputConnection {
         val state = currentSession
         Log.d(TAG, "creating input connection for $state")
-        checkNotNull(state)
+        checkNotNull(state) { "null text state" }
 
         outAttrs.initialSelStart = state.buffer.length
         outAttrs.initialSelEnd = state.buffer.length
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt
new file mode 100644
index 0000000..7cbb03b
--- /dev/null
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/AnchoredDraggableSample.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.samples
+
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.animate
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.AnchoredDraggableState
+import androidx.compose.foundation.gestures.DraggableAnchors
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.anchoredDraggable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import kotlin.math.roundToInt
+
+private enum class AnchoredDraggableSampleValue {
+    Start, Center, End
+}
+
+@Composable
+@Preview
+fun AnchoredDraggableAnchorsFromCompositionSample() {
+    val density = LocalDensity.current
+    val animationSpec = tween<Float>()
+    val positionalThreshold = { distance: Float -> distance * 0.5f }
+    val velocityThreshold = { with(density) { 125.dp.toPx() } }
+    val state = rememberSaveable(
+        density,
+        saver = AnchoredDraggableState.Saver(animationSpec, positionalThreshold, velocityThreshold)
+    ) {
+        AnchoredDraggableState(
+            initialValue = AnchoredDraggableSampleValue.Center,
+            positionalThreshold,
+            velocityThreshold,
+            animationSpec
+        )
+    }
+    val draggableWidth = 70.dp
+    val containerWidthPx = with(density) { draggableWidth.toPx() }
+    // Our anchors depend on the density which is obtained from composition, so we update them using
+    // updateAnchors whenever they are available
+    SideEffect {
+        state.updateAnchors(
+            DraggableAnchors {
+                AnchoredDraggableSampleValue.Start at 0f
+                AnchoredDraggableSampleValue.Center at containerWidthPx / 2f
+                AnchoredDraggableSampleValue.End at containerWidthPx
+            }
+        )
+    }
+    Box(Modifier.width(draggableWidth)) {
+        Box(
+            Modifier
+                .size(100.dp)
+                .offset {
+                    IntOffset(
+                        x = state
+                            .requireOffset()
+                            .roundToInt(), y = 0
+                    )
+                }
+                .anchoredDraggable(state, Orientation.Horizontal)
+                .background(Color.Red)
+        )
+    }
+}
+
+@Preview
+@Composable
+fun AnchoredDraggableLayoutDependentAnchorsSample() {
+    val density = LocalDensity.current
+    val animationSpec = tween<Float>()
+    val positionalThreshold = { distance: Float -> distance * 0.5f }
+    val velocityThreshold = { with(density) { 125.dp.toPx() } }
+    val state = rememberSaveable(
+        density,
+        saver = AnchoredDraggableState.Saver(animationSpec, positionalThreshold, velocityThreshold)
+    ) {
+        AnchoredDraggableState(
+            initialValue = AnchoredDraggableSampleValue.Center,
+            positionalThreshold,
+            velocityThreshold,
+            animationSpec
+        )
+    }
+    val draggableSize = 100.dp
+    val draggableSizePx = with(LocalDensity.current) { draggableSize.toPx() }
+    Box(
+        Modifier
+            .fillMaxWidth()
+            // Our anchors depend on this box's size, so we obtain the size from onSizeChanged and
+            // use updateAnchors to let the state know about the new anchors
+            .onSizeChanged { layoutSize ->
+                val dragEndPoint = layoutSize.width - draggableSizePx
+                state.updateAnchors(
+                    DraggableAnchors {
+                        AnchoredDraggableSampleValue.Start at 0f
+                        AnchoredDraggableSampleValue.Center at dragEndPoint / 2f
+                        AnchoredDraggableSampleValue.End at dragEndPoint
+                    }
+                )
+            }
+    ) {
+        Box(
+            Modifier
+                .size(100.dp)
+                .offset {
+                    IntOffset(
+                        x = state
+                            .requireOffset()
+                            .roundToInt(), y = 0
+                    )
+                }
+                .anchoredDraggable(state, Orientation.Horizontal)
+                .background(Color.Red)
+        )
+    }
+}
+
+@Preview
+@Composable
+fun AnchoredDraggableCustomAnchoredSample() {
+    @Suppress("unused")
+    // Using AnchoredDraggableState's anchoredDrag APIs, we can build a custom animation
+    suspend fun <T> AnchoredDraggableState<T>.customAnimation(
+        target: T,
+        snapAnimationSpec: AnimationSpec<Float>,
+        velocity: Float = lastVelocity,
+    ) {
+        anchoredDrag(target) { latestAnchors, latestTarget ->
+            // If the anchors change while this block is suspending, it will get cancelled and
+            // restarted with the latest anchors and latest target
+            val targetOffset = latestAnchors.positionOf(latestTarget)
+            if (!targetOffset.isNaN()) {
+                animate(
+                    initialValue = offset,
+                    initialVelocity = velocity,
+                    targetValue = targetOffset,
+                    animationSpec = snapAnimationSpec
+                ) { value, velocity ->
+                    dragTo(value, velocity)
+                }
+            }
+        }
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableGestureTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableGestureTest.kt
new file mode 100644
index 0000000..59b8466
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableGestureTest.kt
@@ -0,0 +1,926 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.anchoredDraggable
+
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.AutoTestFrameClock
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.A
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.B
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.C
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.AnchoredDraggableState
+import androidx.compose.foundation.gestures.DraggableAnchors
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.anchoredDraggable
+import androidx.compose.foundation.gestures.animateTo
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.testutils.WithTouchSlop
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.test.swipeWithVelocity
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.abs
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+@OptIn(ExperimentalFoundationApi::class)
+class AnchoredDraggableGestureTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    private val AnchoredDraggableTestTag = "dragbox"
+    private val AnchoredDraggableBoxSize = 200.dp
+
+    @Test
+    fun anchoredDraggable_swipe_horizontal() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
+        state.updateAnchors(anchors)
+
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides NoOpDensity) {
+                WithTouchSlop(0f) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(
+                            Modifier
+                                .requiredSize(AnchoredDraggableBoxSize)
+                                .testTag(AnchoredDraggableTestTag)
+                                .anchoredDraggable(
+                                    state = state,
+                                    orientation = Orientation.Horizontal
+                                )
+                                .offset {
+                                    IntOffset(
+                                        state
+                                            .requireOffset()
+                                            .roundToInt(), 0
+                                    )
+                                }
+                                .background(Color.Red)
+                        )
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentValue).isEqualTo(A)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeRight(endX = right / 2) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeRight(startX = right / 2, endX = right) }
+        rule.waitForIdle()
+        assertThat(state.currentValue).isEqualTo(C)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(C))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeLeft(endX = right / 2) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeLeft(startX = right / 2) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(A))
+    }
+
+    @Test
+    fun anchoredDraggable_swipe_vertical() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
+        state.updateAnchors(anchors)
+
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides NoOpDensity) {
+                WithTouchSlop(0f) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(
+                            Modifier
+                                .requiredSize(AnchoredDraggableBoxSize)
+                                .testTag(AnchoredDraggableTestTag)
+                                .anchoredDraggable(
+                                    state = state,
+                                    orientation = Orientation.Vertical
+                                )
+                                .offset {
+                                    IntOffset(
+                                        state
+                                            .requireOffset()
+                                            .roundToInt(), 0
+                                    )
+                                }
+                                .background(Color.Red)
+                        )
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentValue).isEqualTo(A)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(startY = top, endY = bottom / 2) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(startY = bottom / 2, endY = bottom) }
+        rule.waitForIdle()
+        assertThat(state.currentValue).isEqualTo(C)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(C))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeUp(startY = bottom, endY = bottom / 2) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeUp(startY = bottom / 2, endY = top) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.offset).isEqualTo(anchors.positionOf(A))
+    }
+
+    @Test
+    fun anchoredDraggable_swipe_disabled_horizontal() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
+        state.updateAnchors(anchors)
+
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides NoOpDensity) {
+                WithTouchSlop(0f) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(
+                            Modifier
+                                .requiredSize(AnchoredDraggableBoxSize)
+                                .testTag(AnchoredDraggableTestTag)
+                                .anchoredDraggable(
+                                    state = state,
+                                    orientation = Orientation.Horizontal,
+                                    enabled = false
+                                )
+                                .offset {
+                                    IntOffset(
+                                        state
+                                            .requireOffset()
+                                            .roundToInt(), 0
+                                    )
+                                }
+                                .background(Color.Red)
+                        )
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentValue).isEqualTo(A)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeRight(startX = left, endX = right) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.offset).isZero()
+    }
+
+    @Test
+    fun anchoredDraggable_swipe_disabled_vertical() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
+        state.updateAnchors(anchors)
+
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides NoOpDensity) {
+                WithTouchSlop(0f) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(
+                            Modifier
+                                .requiredSize(AnchoredDraggableBoxSize)
+                                .testTag(AnchoredDraggableTestTag)
+                                .anchoredDraggable(
+                                    state = state,
+                                    orientation = Orientation.Vertical,
+                                    enabled = false
+                                )
+                                .offset {
+                                    IntOffset(
+                                        state
+                                            .requireOffset()
+                                            .roundToInt(), 0
+                                    )
+                                }
+                                .background(Color.Red)
+                        )
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentValue).isEqualTo(A)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(startY = top, endY = bottom) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.offset).isZero()
+    }
+
+    @Test
+    fun anchoredDraggable_positionalThresholds_fractional_targetState() {
+        val positionalThreshold = 0.5f
+        val absThreshold = abs(positionalThreshold)
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = { totalDistance -> totalDistance * positionalThreshold },
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        val positionOfA = state.anchors.positionOf(A)
+        val positionOfB = state.anchors.positionOf(B)
+        val distance = abs(positionOfA - positionOfB)
+        state.dispatchRawDelta(positionOfA + distance * (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        state.dispatchRawDelta(distance * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        state.dispatchRawDelta(-distance * (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        state.dispatchRawDelta(-distance * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_positionalThresholds_fractional_negativeThreshold_targetState() {
+        val positionalThreshold = -0.5f
+        val absThreshold = abs(positionalThreshold)
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = { totalDistance -> totalDistance * positionalThreshold },
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        val positionOfA = state.anchors.positionOf(A)
+        val positionOfB = state.anchors.positionOf(B)
+        val distance = abs(positionOfA - positionOfB)
+        state.dispatchRawDelta(positionOfA + distance * (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        state.dispatchRawDelta(distance * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        state.dispatchRawDelta(-distance * (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        state.dispatchRawDelta(-distance * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_positionalThresholds_fixed_targetState() {
+        val positionalThreshold = 56.dp
+        val positionalThresholdPx = with(rule.density) { positionalThreshold.toPx() }
+        val absThreshold = abs(positionalThresholdPx)
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = { positionalThresholdPx },
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        val initialOffset = state.requireOffset()
+
+        // Swipe towards B, close before threshold
+        state.dispatchRawDelta(initialOffset + (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        // Swipe towards B, close after threshold
+        state.dispatchRawDelta(absThreshold * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Swipe towards A, close before threshold
+        state.dispatchRawDelta(-(absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Swipe towards A, close after threshold
+        state.dispatchRawDelta(-(absThreshold * 0.2f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_positionalThresholds_fixed_negativeThreshold_targetState() {
+        val positionalThreshold = (-56).dp
+        val positionalThresholdPx = with(rule.density) { positionalThreshold.toPx() }
+        val absThreshold = abs(positionalThresholdPx)
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = { positionalThresholdPx },
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        val initialOffset = state.requireOffset()
+
+        // Swipe towards B, close before threshold
+        state.dispatchRawDelta(initialOffset + (absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        // Swipe towards B, close after threshold
+        state.dispatchRawDelta(absThreshold * 0.2f)
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Swipe towards A, close before threshold
+        state.dispatchRawDelta(-(absThreshold * 0.9f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Swipe towards A, close after threshold
+        state.dispatchRawDelta(-(absThreshold * 0.2f))
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        runBlocking(AutoTestFrameClock()) { state.settle(velocity = 0f) }
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_velocityThreshold_settle_velocityHigherThanThreshold_advances() =
+        runBlocking(AutoTestFrameClock()) {
+            val velocity = 100.dp
+            val velocityPx = with(rule.density) { velocity.toPx() }
+            val state = AnchoredDraggableState(
+                initialValue = A,
+                positionalThreshold = DefaultPositionalThreshold,
+                velocityThreshold = { velocityPx / 2f },
+                animationSpec = tween()
+            )
+            state.updateAnchors(
+                DraggableAnchors {
+                    A at 0f
+                    B at 100f
+                    C at 200f
+                }
+            )
+            state.dispatchRawDelta(60f)
+            state.settle(velocityPx)
+            rule.waitForIdle()
+            assertThat(state.currentValue).isEqualTo(B)
+        }
+
+    @Test
+    fun anchoredDraggable_velocityThreshold_settle_velocityLowerThanThreshold_doesntAdvance() =
+        runBlocking(AutoTestFrameClock()) {
+            val velocity = 100.dp
+            val velocityPx = with(rule.density) { velocity.toPx() }
+            val state = AnchoredDraggableState(
+                initialValue = A,
+                velocityThreshold = { velocityPx },
+                positionalThreshold = { Float.POSITIVE_INFINITY },
+                animationSpec = tween()
+            )
+            state.updateAnchors(
+                DraggableAnchors {
+                    A at 0f
+                    B at 100f
+                    C at 200f
+                }
+            )
+            state.dispatchRawDelta(60f)
+            state.settle(velocityPx / 2)
+            assertThat(state.currentValue).isEqualTo(A)
+        }
+
+    @Test
+    fun anchoredDraggable_velocityThreshold_swipe_velocityHigherThanThreshold_advances() {
+        val velocityThreshold = 100.dp
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = { with(rule.density) { velocityThreshold.toPx() } },
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput {
+                swipeWithVelocity(
+                    start = Offset(left, 0f),
+                    end = Offset(right / 2, 0f),
+                    endVelocity = with(rule.density) { velocityThreshold.toPx() } * 1.1f
+                )
+            }
+
+        rule.waitForIdle()
+        assertThat(state.currentValue).isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_velocityThreshold_swipe_velocityLowerThanThreshold_doesntAdvance() {
+        val velocityThreshold = 100.dp
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            velocityThreshold = { with(rule.density) { velocityThreshold.toPx() } },
+            positionalThreshold = { Float.POSITIVE_INFINITY },
+            animationSpec = tween()
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
+                            state.updateAnchors(anchors)
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput {
+                swipeWithVelocity(
+                    start = Offset(left, 0f),
+                    end = Offset(right / 2, 0f),
+                    endVelocity = with(rule.density) { velocityThreshold.toPx() } * 0.9f
+                )
+            }
+
+        rule.waitForIdle()
+        assertThat(state.currentValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_dragBeyondBounds_clampsAndSwipesBack() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            C at 500f
+        }
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = DefaultPositionalThreshold,
+            velocityThreshold = { 0f },
+            animationSpec = tween()
+        )
+        state.updateAnchors(anchors)
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        val overdrag = 100f
+        val maxBound = state.anchors.positionOf(C)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput {
+                down(Offset(0f, 0f))
+                moveBy(Offset(x = maxBound + overdrag, y = 0f))
+                moveBy(Offset(x = -overdrag, y = 0f))
+            }
+
+        rule.waitForIdle()
+
+        // If we have not correctly coerced our drag deltas, its internal offset would be the
+        // max bound + overdrag. If it is coerced correctly, it will not move past the max bound.
+        // This means that once we swipe back by the amount of overdrag, we should end up at the
+        // max bound - overdrag.
+        assertThat(state.requireOffset()).isEqualTo(maxBound - overdrag)
+    }
+
+    @Test
+    fun anchoredDraggable_animationCancelledByDrag_resetsTargetValueToClosest() {
+        rule.mainClock.autoAdvance = false
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = { totalDistance -> totalDistance * 0.5f },
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
+        )
+        state.updateAnchors(anchors)
+        lateinit var scope: CoroutineScope
+        rule.setContent {
+            WithTouchSlop(touchSlop = 0f) {
+                scope = rememberCoroutineScope()
+                Box(Modifier.fillMaxSize()) {
+                    Box(
+                        Modifier
+                            .requiredSize(AnchoredDraggableBoxSize)
+                            .testTag(AnchoredDraggableTestTag)
+                            .anchoredDraggable(
+                                state = state,
+                                orientation = Orientation.Horizontal
+                            )
+                            .offset {
+                                IntOffset(
+                                    state
+                                        .requireOffset()
+                                        .roundToInt(), 0
+                                )
+                            }
+                            .background(Color.Red)
+                    )
+                }
+            }
+        }
+
+        assertThat(state.currentValue).isEqualTo(A)
+        assertThat(state.targetValue).isEqualTo(A)
+
+        scope.launch { state.animateTo(C) }
+
+        rule.mainClock.advanceTimeUntil {
+            state.requireOffset() > abs(state.requireOffset() - anchors.positionOf(B))
+        } // Advance until our closest anchor is B
+        assertThat(state.targetValue).isEqualTo(C)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput {
+                down(Offset.Zero)
+            }
+
+        assertThat(state.targetValue).isEqualTo(B) // B is the closest now so we should target it
+    }
+
+    private val DefaultPositionalThreshold: (totalDistance: Float) -> Float = {
+        with(rule.density) { 56.dp.toPx() }
+    }
+
+    private val DefaultVelocityThreshold: () -> Float = { with(rule.density) { 125.dp.toPx() } }
+}
+
+private val NoOpDensity = object : Density {
+    override val density = 1f
+    override val fontScale = 1f
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableStateTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableStateTest.kt
new file mode 100644
index 0000000..6565d4e
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableStateTest.kt
@@ -0,0 +1,986 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.anchoredDraggable
+
+import androidx.compose.animation.core.FloatSpringSpec
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.A
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.B
+import androidx.compose.foundation.anchoredDraggable.AnchoredDraggableTestValue.C
+import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.AnchoredDraggableState
+import androidx.compose.foundation.gestures.DraggableAnchors
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.anchoredDraggable
+import androidx.compose.foundation.gestures.animateTo
+import androidx.compose.foundation.gestures.snapTo
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.text.matchers.isZero
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MonotonicFrameClock
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.runtime.withFrameNanos
+import androidx.compose.testutils.WithTouchSlop
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.StateRestorationTester
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.TimeUnit
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.test.runTest
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+@OptIn(ExperimentalFoundationApi::class)
+class AnchoredDraggableStateTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    private val AnchoredDraggableTestTag = "dragbox"
+    private val AnchoredDraggableBoxSize = 200.dp
+
+    @Test
+    fun anchoredDraggable_state_canSkipStateByFling() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Vertical
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown() }
+
+        rule.waitForIdle()
+
+        assertThat(state.currentValue).isEqualTo(C)
+    }
+
+    @Test
+    fun anchoredDraggable_targetState_updatedOnSwipe() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Vertical
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(endY = bottom * 0.45f) }
+        rule.waitForIdle()
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Assert that swipe below threshold upward settles at current state
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeUp(endY = bottom * 0.95f, durationMillis = 1000) }
+        rule.waitForIdle()
+        assertThat(state.targetValue).isEqualTo(B)
+
+        // Assert that swipe below threshold downward settles at current state
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(endY = bottom * 0.05f) }
+        rule.waitForIdle()
+        assertThat(state.targetValue).isEqualTo(B)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(endY = bottom * 0.9f) }
+        rule.waitForIdle()
+        assertThat(state.targetValue).isEqualTo(C)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeUp(endY = top * 1.1f) }
+        rule.waitForIdle()
+        assertThat(state.targetValue).isEqualTo(A)
+    }
+
+    @Test
+    fun anchoredDraggable_targetState_updatedWithAnimation() {
+        rule.mainClock.autoAdvance = false
+        val animationDuration = 300
+        val frameLengthMillis = 16L
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            animationSpec = tween(animationDuration, easing = LinearEasing),
+            positionalThreshold = { distance -> distance * 0.5f },
+            velocityThreshold = defaultVelocityThreshold
+        )
+        lateinit var scope: CoroutineScope
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Vertical
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        scope.launch {
+            state.animateTo(targetValue = B)
+        }
+        rule.mainClock.advanceTimeBy(1 * frameLengthMillis)
+
+        assertWithMessage("Current state")
+            .that(state.currentValue)
+            .isEqualTo(A)
+        assertWithMessage("Target state")
+            .that(state.targetValue)
+            .isEqualTo(B)
+
+        rule.mainClock.autoAdvance = true
+        rule.waitForIdle()
+
+        assertWithMessage("Current state")
+            .that(state.currentValue)
+            .isEqualTo(B)
+        assertWithMessage("Target state")
+            .that(state.targetValue)
+            .isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_progress_matchesSwipePosition() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        rule.setContent {
+            WithTouchSlop(touchSlop = 0f) {
+                Box(Modifier.fillMaxSize()) {
+                    Box(
+                        Modifier
+                            .requiredSize(AnchoredDraggableBoxSize)
+                            .testTag(AnchoredDraggableTestTag)
+                            .anchoredDraggable(
+                                state = state,
+                                orientation = Orientation.Vertical
+                            )
+                            .onSizeChanged { layoutSize ->
+                                state.updateAnchors(
+                                    DraggableAnchors {
+                                        A at 0f
+                                        B at layoutSize.width / 2f
+                                        C at layoutSize.width.toFloat()
+                                    }
+                                )
+                            }
+                            .offset {
+                                IntOffset(
+                                    state
+                                        .requireOffset()
+                                        .roundToInt(), 0
+                                )
+                            }
+                            .background(Color.Red)
+                    )
+                }
+            }
+        }
+
+        val anchorA = state.anchors.positionOf(A)
+        val anchorB = state.anchors.positionOf(B)
+        val almostAnchorB = anchorB * 0.9f
+        var expectedProgress = almostAnchorB / (anchorB - anchorA)
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeDown(endY = almostAnchorB) }
+
+        assertThat(state.targetValue).isEqualTo(B)
+        assertThat(state.progress).isEqualTo(expectedProgress)
+
+        val almostAnchorA = anchorA + ((anchorB - anchorA) * 0.1f)
+        expectedProgress = 1 - (almostAnchorA / (anchorB - anchorA))
+
+        rule.onNodeWithTag(AnchoredDraggableTestTag)
+            .performTouchInput { swipeUp(startY = anchorB, endY = almostAnchorA) }
+
+        assertThat(state.targetValue).isEqualTo(A)
+        assertThat(state.progress).isEqualTo(expectedProgress)
+    }
+
+    @Test
+    fun anchoredDraggable_snapTo_updatesImmediately() = runBlocking {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Vertical
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        state.snapTo(C)
+        assertThat(state.currentValue)
+            .isEqualTo(C)
+    }
+
+    @Test
+    fun anchoredDraggable_rememberanchoredDraggableState_restored() {
+        val restorationTester = StateRestorationTester(rule)
+
+        val initialState = C
+        val animationSpec = tween<Float>(durationMillis = 1000)
+        val state = AnchoredDraggableState(
+            initialValue = initialState,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = animationSpec
+        )
+        lateinit var scope: CoroutineScope
+
+        restorationTester.setContent {
+            SideEffect {
+                state.updateAnchors(
+                    DraggableAnchors {
+                        A at 0f
+                        B at 100f
+                        C at 200f
+                    }
+                )
+            }
+            scope = rememberCoroutineScope()
+        }
+
+        restorationTester.emulateSavedInstanceStateRestore()
+
+        assertThat(state.currentValue).isEqualTo(initialState)
+        assertThat(state.animationSpec).isEqualTo(animationSpec)
+
+        scope.launch {
+            state.animateTo(B)
+        }
+        rule.waitForIdle()
+        assertThat(state.currentValue).isEqualTo(B)
+
+        restorationTester.emulateSavedInstanceStateRestore()
+        assertThat(state.currentValue).isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_targetState_accessedInInitialComposition() {
+        lateinit var targetState: AnchoredDraggableTestValue
+        rule.setContent {
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
+            LaunchedEffect(state.targetValue) {
+                targetState = state.targetValue
+            }
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        assertThat(targetState).isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_progress_accessedInInitialComposition() {
+        var progress = Float.NaN
+        rule.setContent {
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
+            LaunchedEffect(state.progress) {
+                progress = state.progress
+            }
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        assertThat(progress).isEqualTo(1f)
+    }
+
+    @Test
+    @Ignore("Todo: Fix differences between tests and real code - this shouldn't work :)")
+    fun anchoredDraggable_requireOffset_accessedInInitialComposition_throws() {
+        var exception: Throwable? = null
+        val state = AnchoredDraggableState(
+            initialValue = B,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        var offset: Float? = null
+        rule.setContent {
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Horizontal
+                        )
+                        .onSizeChanged { layoutSize ->
+                            state.updateAnchors(
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
+                            )
+                        }
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+            exception = runCatching { offset = state.requireOffset() }.exceptionOrNull()
+        }
+
+        assertThat(state.anchors.size).isNotEqualTo(0)
+        assertThat(offset).isNull()
+        assertThat(exception).isNotNull()
+        assertThat(exception).isInstanceOf(IllegalStateException::class.java)
+        assertThat(exception).hasMessageThat().contains("offset")
+    }
+
+    @Test
+    @Ignore("LaunchedEffects execute instantly in tests. How can we delay?")
+    fun anchoredDraggable_requireOffset_accessedInEffect_doesntThrow() {
+        var exception: Throwable? = null
+        rule.setContent {
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
+            LaunchedEffect(Unit) {
+                exception = runCatching { state.requireOffset() }.exceptionOrNull()
+            }
+        }
+
+        assertThat(exception).isNull()
+    }
+
+    @Test
+    fun anchoredDraggable_animateTo_animatesBeyondBounds() {
+        rule.mainClock.autoAdvance = false
+        val minBound = 0f
+        val maxBound = 500f
+        val anchors = DraggableAnchors {
+            A at minBound
+            C at maxBound
+        }
+
+        val animationSpec = FloatSpringSpec(dampingRatio = Spring.DampingRatioHighBouncy)
+        val animationDuration = animationSpec.getDurationNanos(
+            initialValue = minBound,
+            targetValue = maxBound,
+            initialVelocity = 0f
+        ).let { TimeUnit.NANOSECONDS.toMillis(it) }
+
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = animationSpec
+        )
+        lateinit var scope: CoroutineScope
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            SideEffect {
+                state.updateAnchors(anchors)
+            }
+            Box(Modifier.fillMaxSize()) {
+                Box(
+                    Modifier
+                        .requiredSize(AnchoredDraggableBoxSize)
+                        .testTag(AnchoredDraggableTestTag)
+                        .anchoredDraggable(
+                            state = state,
+                            orientation = Orientation.Vertical
+                        )
+                        .offset {
+                            IntOffset(
+                                state
+                                    .requireOffset()
+                                    .roundToInt(), 0
+                            )
+                        }
+                        .background(Color.Red)
+                )
+            }
+        }
+
+        scope.launch {
+            state.animateTo(C)
+        }
+        var highestOffset = 0f
+        for (i in 0..animationDuration step 16) {
+            highestOffset = state.requireOffset()
+            rule.mainClock.advanceTimeBy(16)
+        }
+        assertThat(highestOffset).isGreaterThan(anchors.positionOf(C))
+    }
+
+    @Test
+    fun anchoredDraggable_targetNotInAnchors_animateTo_updatesCurrentValue() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        assertThat(state.anchors.size).isEqualTo(0)
+        assertThat(state.currentValue).isEqualTo(A)
+        runBlocking { state.animateTo(B) }
+        assertThat(state.currentValue).isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_targetNotInAnchors_snapTo_updatesCurrentValue() {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        assertThat(state.anchors.size).isEqualTo(0)
+        assertThat(state.currentValue).isEqualTo(A)
+        runBlocking { state.snapTo(B) }
+        assertThat(state.currentValue).isEqualTo(B)
+    }
+
+    @Test
+    fun anchoredDraggable_updateAnchors_noOngoingDrag_shouldUpdateOffset() {
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+
+        assertThat(anchoredDraggableState.currentValue).isEqualTo(A)
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(A)
+        assertThat(anchoredDraggableState.offset).isNaN()
+
+        val offsetAtB = 100f
+        anchoredDraggableState.updateAnchors(
+            newAnchors = DraggableAnchors {
+                A at 0f
+                B at offsetAtB
+            },
+            newTarget = B
+        )
+        assertThat(anchoredDraggableState.currentValue).isEqualTo(B)
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(B)
+        assertThat(anchoredDraggableState.offset).isEqualTo(offsetAtB)
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_updateAnchors_ongoingDrag_shouldRestartDrag() = runTest {
+        // Given an anchored draggable state
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = 1,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+
+        val anchorUpdates = Channel<DraggableAnchors<Int>>()
+        val dragJob = launch {
+            anchoredDraggableState.anchoredDrag { newAnchors ->
+                anchorUpdates.send(newAnchors)
+                suspendIndefinitely()
+            }
+        }
+
+        val firstAnchors = anchorUpdates.receive()
+        assertThat(firstAnchors.size).isZero()
+
+        // When the anchors change
+        val newAnchors = DraggableAnchors {
+            1 at 100f
+            2 at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors)
+        }
+
+        // Then the block should be invoked with the new anchors
+        assertThat(dragJob.isActive).isTrue()
+        val secondAnchors = anchorUpdates.receive()
+        assertThat(secondAnchors).isEqualTo(newAnchors)
+        dragJob.cancel()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_updateAnchors_anchoredDrag_invokedWithLatestAnchors() = runTest {
+        // Given an anchored draggable state
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = 1,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+
+        val anchorUpdates = Channel<DraggableAnchors<Int>>()
+        val dragJob = launch(Dispatchers.Unconfined) {
+            anchoredDraggableState.anchoredDrag { newAnchors ->
+                anchorUpdates.send(newAnchors)
+                suspendIndefinitely()
+            }
+        }
+
+        val firstAnchors = anchorUpdates.receive()
+        assertThat(firstAnchors.size).isZero()
+
+        // When the anchors change
+        val newAnchors = DraggableAnchors {
+            1 at 100f
+            2 at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors)
+        }
+
+        // Then the block should be invoked with the new anchors
+        assertThat(dragJob.isActive).isTrue()
+        val secondAnchors = anchorUpdates.receive()
+        assertThat(secondAnchors).isEqualTo(newAnchors)
+        dragJob.cancel()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_updateAnchors_anchoredDrag_invokedWithLatestTarget() = runTest {
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = A,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        anchoredDraggableState.updateAnchors(
+            DraggableAnchors {
+                A at 0f
+                B at 200f
+            }
+        )
+
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(A)
+
+        val firstExpectedTarget = B
+        val targetUpdates = Channel<AnchoredDraggableTestValue>()
+        val dragJob = launch(Dispatchers.Unconfined) {
+            anchoredDraggableState.anchoredDrag(firstExpectedTarget) { _, latestTarget ->
+                targetUpdates.send(latestTarget)
+                suspendIndefinitely()
+            }
+        }
+
+        val firstTarget = targetUpdates.receive()
+        assertThat(firstTarget).isEqualTo(firstExpectedTarget)
+
+        // When the anchors and target change
+        val newTarget = A
+        val newAnchors = DraggableAnchors {
+            A at 100f
+            B at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors, newTarget)
+        }
+
+        // Then the block should be invoked with the new anchors
+        val secondTarget = targetUpdates.receive()
+        assertThat(secondTarget).isEqualTo(newTarget)
+        dragJob.cancel()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_dragCompletesExceptionally_cleansUp() = runTest {
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = A,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        val cancellationSignal = CompletableDeferred(false)
+        val anchoredDragUpdates = Channel<Unit>()
+        val dragJob = launch {
+            anchoredDraggableState.anchoredDrag {
+                anchoredDragUpdates.send(Unit)
+                cancellationSignal.await()
+                cancel()
+            }
+        }
+
+        assertThat(dragJob.isActive).isTrue()
+        assertThat(anchoredDragUpdates.receive()).isEqualTo(Unit)
+        cancellationSignal.complete(true)
+        dragJob.join()
+        assertThat(dragJob.isCancelled).isTrue()
+    }
+
+    @Test
+    fun anchoredDraggable_customDrag_updatesOffset() = runBlocking {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
+
+        state.updateAnchors(anchors)
+        state.anchoredDrag {
+            dragTo(150f)
+        }
+
+        assertThat(state.requireOffset()).isEqualTo(150f)
+
+        state.anchoredDrag {
+            dragTo(250f)
+        }
+        assertThat(state.requireOffset()).isEqualTo(250f)
+    }
+
+    @Test
+    fun anchoredDraggable_customDrag_updatesVelocity() = runBlocking {
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
+
+        state.updateAnchors(anchors)
+        state.anchoredDrag {
+            dragTo(150f, lastKnownVelocity = 454f)
+        }
+        assertThat(state.lastVelocity).isEqualTo(454f)
+    }
+
+    @Test
+    fun anchoredDraggable_customDrag_targetValueUpdate() = runBlocking {
+        val clock = HandPumpTestFrameClock()
+        val dragScope = CoroutineScope(clock)
+
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
+
+        state.updateAnchors(anchors)
+        dragScope.launch(start = CoroutineStart.UNDISPATCHED) {
+            state.anchoredDrag(targetValue = C) { _, _ ->
+                while (isActive) {
+                    withFrameNanos {
+                        dragTo(200f)
+                    }
+                }
+            }
+        }
+        clock.advanceByFrame()
+        assertThat(state.targetValue).isEqualTo(C)
+        dragScope.cancel()
+    }
+
+    @Test
+    fun anchoredDraggable_constructorWithAnchors_updatesAnchorsAndInitializes() {
+        val initialValueOffset = 0f
+        val anchors = DraggableAnchors {
+            A at initialValueOffset
+            B at 200f
+        }
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            anchors = anchors,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        assertThat(state.anchors).isEqualTo(anchors)
+        assertThat(state.offset).isEqualTo(initialValueOffset)
+    }
+
+    @Test
+    fun anchoredDraggable_constructorWithAnchors_initialValueNotInAnchors_updatesCurrentValue() {
+        val anchors = DraggableAnchors { B at 200f }
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            anchors = anchors,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        assertThat(state.anchors).isEqualTo(anchors)
+        assertThat(state.offset).isNaN()
+    }
+
+    private suspend fun suspendIndefinitely() = suspendCancellableCoroutine<Unit> { }
+
+    private class HandPumpTestFrameClock : MonotonicFrameClock {
+        private val frameCh = Channel<Long>(1)
+
+        suspend fun advanceByFrame() {
+            frameCh.send(16_000_000L)
+        }
+
+        override suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R {
+            return onFrame(frameCh.receive())
+        }
+    }
+
+    private val defaultPositionalThreshold: (totalDistance: Float) -> Float = {
+        with(rule.density) { 56.dp.toPx() }
+    }
+
+    private val defaultVelocityThreshold: () -> Float = { with(rule.density) { 125.dp.toPx() } }
+
+    private val defaultAnimationSpec = tween<Float>()
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableTestValue.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableTestValue.kt
new file mode 100644
index 0000000..54bfc02
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/anchoredDraggable/AnchoredDraggableTestValue.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.compose.foundation.anchoredDraggable
+
+internal enum class AnchoredDraggableTestValue { A, B, C }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
index eddfb44..3498cb7 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutPrefetcher.android.kt
@@ -156,7 +156,7 @@
                     }
                 }
             } else {
-                check(!request.measured)
+                check(!request.measured) { "request already measured" }
                 trace("compose:lazylist:prefetch:measure") {
                     val beforeTimeNs = System.nanoTime()
                     if (enoughTimeLeft(beforeTimeNs, nextFrameNs, timeTracker.measurementTimeNs)) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/MutatorMutex.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/MutatorMutex.kt
index ee7b694..f8fd5fb 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/MutatorMutex.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/MutatorMutex.kt
@@ -176,4 +176,38 @@
             }
         }
     }
+
+    /**
+     * Attempt to mutate synchronously if there is no other active caller.
+     * If there is no other active caller, the [block] will be executed in a lock. If there is
+     * another active caller, this method will return false, indicating that the active caller
+     * needs to be cancelled through a [mutate] or [mutateWith] call with an equal or higher
+     * mutation priority.
+     *
+     * Calls to [mutate] and [mutateWith] will suspend until execution of the [block] has finished.
+     *
+     * @param block mutation code to run mutually exclusive with any other call to [mutate],
+     * [mutateWith] or [tryMutate].
+     * @return true if the [block] was executed, false if there was another active caller and the
+     * [block] was not executed.
+     */
+    inline fun tryMutate(block: () -> Unit): Boolean {
+        val didLock = tryLock()
+        if (didLock) {
+            try {
+                block()
+            } finally {
+                unlock()
+            }
+        }
+        return didLock
+    }
+
+    @PublishedApi
+    internal fun tryLock(): Boolean = mutex.tryLock()
+
+    @PublishedApi
+    internal fun unlock() {
+        mutex.unlock()
+    }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
new file mode 100644
index 0000000..8bb9b13f
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/AnchoredDraggable.kt
@@ -0,0 +1,770 @@
+/*
+ * 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.compose.foundation.gestures
+
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.animate
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.MutatePriority
+import androidx.compose.foundation.MutatorMutex
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.offset
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.runtime.structuralEqualityPolicy
+import androidx.compose.ui.Modifier
+import kotlin.math.abs
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Structure that represents the anchors of a [AnchoredDraggableState].
+ *
+ * See the DraggableAnchors factory method to construct drag anchors using a default implementation.
+ */
+@ExperimentalFoundationApi
+interface DraggableAnchors<T> {
+
+    /**
+     * Get the anchor position for an associated [value]
+     *
+     * @param value The value to look up
+     *
+     * @return The position of the anchor, or [Float.NaN] if the anchor does not exist
+     */
+    fun positionOf(value: T): Float
+
+    /**
+     * Whether there is an anchor position associated with the [value]
+     *
+     * @param value The value to look up
+     *
+     * @return true if there is an anchor for this value, false if there is no anchor for this value
+     */
+    fun hasAnchorFor(value: T): Boolean
+
+    /**
+     * Find the closest anchor to the [position].
+     *
+     * @param position The position to start searching from
+     *
+     * @return The closest anchor or null if the anchors are empty
+     */
+    fun closestAnchor(position: Float): T?
+
+    /**
+     * Find the closest anchor to the [position], in the specified direction.
+     *
+     * @param position The position to start searching from
+     * @param searchUpwards Whether to search upwards from the current position or downwards
+     *
+     * @return The closest anchor or null if the anchors are empty
+     */
+    fun closestAnchor(position: Float, searchUpwards: Boolean): T?
+
+    /**
+     * The smallest anchor, or [Float.NEGATIVE_INFINITY] if the anchors are empty.
+     */
+    fun minAnchor(): Float
+
+    /**
+     * The biggest anchor, or [Float.POSITIVE_INFINITY] if the anchors are empty.
+     */
+    fun maxAnchor(): Float
+
+    /**
+     * The amount of anchors
+     */
+    val size: Int
+}
+
+/**
+ * [DraggableAnchorsConfig] stores a mutable configuration anchors, comprised of values of [T] and
+ * corresponding [Float] positions. This [DraggableAnchorsConfig] is used to construct an immutable
+ * [DraggableAnchors] instance later on.
+ */
+@ExperimentalFoundationApi
+class DraggableAnchorsConfig<T> {
+
+    internal val anchors = mutableMapOf<T, Float>()
+
+    /**
+     * Set the anchor position for [this] anchor.
+     *
+     * @param position The anchor position.
+     */
+    @Suppress("BuilderSetStyle")
+    infix fun T.at(position: Float) {
+        anchors[this] = position
+    }
+}
+
+/**
+ * Create a new [DraggableAnchors] instance using a builder function.
+ *
+ * @param builder A function with a [DraggableAnchorsConfig] that offers APIs to configure anchors
+ * @return A new [DraggableAnchors] instance with the anchor positions set by the `builder`
+ * function.
+ */
+@ExperimentalFoundationApi
+fun <T : Any> DraggableAnchors(
+    builder: DraggableAnchorsConfig<T>.() -> Unit
+): DraggableAnchors<T> = MapDraggableAnchors(DraggableAnchorsConfig<T>().apply(builder).anchors)
+
+/**
+ * Enable drag gestures between a set of predefined values.
+ *
+ * When a drag is detected, the offset of the [AnchoredDraggableState] will be updated with the drag
+ * delta. You should use this offset to move your content accordingly (see [Modifier.offset]).
+ * When the drag ends, the offset will be animated to one of the anchors and when that anchor is
+ * reached, the value of the [AnchoredDraggableState] will also be updated to the value
+ * corresponding to the new anchor.
+ *
+ * Dragging is constrained between the minimum and maximum anchors.
+ *
+ * @param state The associated [AnchoredDraggableState].
+ * @param orientation The orientation in which the [anchoredDraggable] can be dragged.
+ * @param enabled Whether this [anchoredDraggable] is enabled and should react to the user's input.
+ * @param reverseDirection Whether to reverse the direction of the drag, so a top to bottom
+ * drag will behave like bottom to top, and a left to right drag will behave like right to left.
+ * @param interactionSource Optional [MutableInteractionSource] that will passed on to
+ * the internal [Modifier.draggable].
+ */
+@ExperimentalFoundationApi
+fun <T> Modifier.anchoredDraggable(
+    state: AnchoredDraggableState<T>,
+    orientation: Orientation,
+    enabled: Boolean = true,
+    reverseDirection: Boolean = false,
+    interactionSource: MutableInteractionSource? = null
+) = draggable(
+    state = state.draggableState,
+    orientation = orientation,
+    enabled = enabled,
+    interactionSource = interactionSource,
+    reverseDirection = reverseDirection,
+    startDragImmediately = state.isAnimationRunning,
+    onDragStopped = { velocity -> launch { state.settle(velocity) } }
+)
+
+/**
+ * Scope used for suspending anchored drag blocks. Allows to set [AnchoredDraggableState.offset] to
+ * a new value.
+ *
+ * @see [AnchoredDraggableState.anchoredDrag] to learn how to start the anchored drag and get the
+ * access to this scope.
+ */
+@ExperimentalFoundationApi
+interface AnchoredDragScope {
+    /**
+     * Assign a new value for an offset value for [AnchoredDraggableState].
+     *
+     * @param newOffset new value for [AnchoredDraggableState.offset].
+     * @param lastKnownVelocity last known velocity (if known)
+     */
+    fun dragTo(
+        newOffset: Float,
+        lastKnownVelocity: Float = 0f
+    )
+}
+
+/**
+ * State of the [anchoredDraggable] modifier.
+ * Use the constructor overload with anchors if the anchors are defined in composition, or update
+ * the anchors using [updateAnchors].
+ *
+ * This contains necessary information about any ongoing drag or animation and provides methods
+ * to change the state either immediately or by starting an animation.
+ *
+ * @param initialValue The initial value of the state.
+ * @param positionalThreshold The positional threshold, in px, to be used when calculating the
+ * target state while a drag is in progress and when settling after the drag ends. This is the
+ * distance from the start of a transition. It will be, depending on the direction of the
+ * interaction, added or subtracted from/to the origin offset. It should always be a positive value.
+ * @param velocityThreshold The velocity threshold (in px per second) that the end velocity has to
+ * exceed in order to animate to the next state, even if the [positionalThreshold] has not been
+ * reached.
+ * @param animationSpec The default animation that will be used to animate to a new state.
+ * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
+ */
+@Stable
+@ExperimentalFoundationApi
+class AnchoredDraggableState<T>(
+    initialValue: T,
+    @Suppress("PrimitiveInLambda")
+    internal val positionalThreshold: (totalDistance: Float) -> Float,
+    @Suppress("PrimitiveInLambda")
+    internal val velocityThreshold: () -> Float,
+    val animationSpec: AnimationSpec<Float>,
+    internal val confirmValueChange: (newValue: T) -> Boolean = { true }
+) {
+
+    /**
+     * Construct an [AnchoredDraggableState] instance with anchors.
+     *
+     * @param initialValue The initial value of the state.
+     * @param anchors The anchors of the state. Use [updateAnchors] to update the anchors later.
+     * @param animationSpec The default animation that will be used to animate to a new state.
+     * @param confirmValueChange Optional callback invoked to confirm or veto a pending state
+     * change.
+     * @param positionalThreshold The positional threshold, in px, to be used when calculating the
+     * target state while a drag is in progress and when settling after the drag ends. This is the
+     * distance from the start of a transition. It will be, depending on the direction of the
+     * interaction, added or subtracted from/to the origin offset. It should always be a positive
+     * value.
+     * @param velocityThreshold The velocity threshold (in px per second) that the end velocity has
+     * to exceed in order to animate to the next state, even if the [positionalThreshold] has not
+     * been reached.
+     */
+    @ExperimentalFoundationApi
+    constructor(
+        initialValue: T,
+        anchors: DraggableAnchors<T>,
+        @Suppress("PrimitiveInLambda")
+        positionalThreshold: (totalDistance: Float) -> Float,
+        @Suppress("PrimitiveInLambda")
+        velocityThreshold: () -> Float,
+        animationSpec: AnimationSpec<Float>,
+        confirmValueChange: (newValue: T) -> Boolean = { true }
+    ) : this(
+        initialValue,
+        positionalThreshold,
+        velocityThreshold,
+        animationSpec,
+        confirmValueChange
+    ) {
+        this.anchors = anchors
+        trySnapTo(initialValue)
+    }
+
+    private val dragMutex = MutatorMutex()
+
+    internal val draggableState = object : DraggableState {
+
+        private val dragScope = object : DragScope {
+            override fun dragBy(pixels: Float) {
+                with(anchoredDragScope) {
+                    dragTo(newOffsetForDelta(pixels))
+                }
+            }
+        }
+
+        override suspend fun drag(
+            dragPriority: MutatePriority,
+            block: suspend DragScope.() -> Unit
+        ) {
+            this@AnchoredDraggableState.anchoredDrag(dragPriority) {
+                with(dragScope) { block() }
+            }
+        }
+
+        override fun dispatchRawDelta(delta: Float) {
+            this@AnchoredDraggableState.dispatchRawDelta(delta)
+        }
+    }
+
+    /**
+     * The current value of the [AnchoredDraggableState].
+     */
+    var currentValue: T by mutableStateOf(initialValue)
+        private set
+
+    /**
+     * The target value. This is the closest value to the current offset, taking into account
+     * positional thresholds. If no interactions like animations or drags are in progress, this
+     * will be the current value.
+     */
+    val targetValue: T by derivedStateOf {
+        dragTarget ?: run {
+            val currentOffset = offset
+            if (!currentOffset.isNaN()) {
+                computeTarget(currentOffset, currentValue, velocity = 0f)
+            } else currentValue
+        }
+    }
+
+    /**
+     * The closest value in the swipe direction from the current offset, not considering thresholds.
+     * If an [anchoredDrag] is in progress, this will be the target of that anchoredDrag (if
+     * specified).
+     */
+    internal val closestValue: T by derivedStateOf {
+        dragTarget ?: run {
+            val currentOffset = offset
+            if (!currentOffset.isNaN()) {
+                computeTargetWithoutThresholds(currentOffset, currentValue)
+            } else currentValue
+        }
+    }
+
+    /**
+     * The current offset, or [Float.NaN] if it has not been initialized yet.
+     *
+     * The offset will be initialized when the anchors are first set through [updateAnchors].
+     *
+     * Strongly consider using [requireOffset] which will throw if the offset is read before it is
+     * initialized. This helps catch issues early in your workflow.
+     */
+    var offset: Float by mutableFloatStateOf(Float.NaN)
+        private set
+
+    /**
+     * Require the current offset.
+     *
+     * @see offset
+     *
+     * @throws IllegalStateException If the offset has not been initialized yet
+     */
+    fun requireOffset(): Float {
+        check(!offset.isNaN()) {
+            "The offset was read before being initialized. Did you access the offset in a phase " +
+                "before layout, like effects or composition?"
+        }
+        return offset
+    }
+
+    /**
+     * Whether an animation is currently in progress.
+     */
+    val isAnimationRunning: Boolean get() = dragTarget != null
+
+    /**
+     * The fraction of the progress going from [currentValue] to [closestValue], within [0f..1f]
+     * bounds, or 1f if the [AnchoredDraggableState] is in a settled state.
+     */
+    /*@FloatRange(from = 0f, to = 1f)*/
+    val progress: Float by derivedStateOf(structuralEqualityPolicy()) {
+        val a = anchors.positionOf(currentValue)
+        val b = anchors.positionOf(closestValue)
+        val distance = abs(b - a)
+        if (!distance.isNaN() && distance > 1e-6f) {
+            val progress = (this.requireOffset() - a) / (b - a)
+            // If we are very close to 0f or 1f, we round to the closest
+            if (progress < 1e-6f) 0f else if (progress > 1 - 1e-6f) 1f else progress
+        } else 1f
+    }
+
+    /**
+     * The velocity of the last known animation. Gets reset to 0f when an animation completes
+     * successfully, but does not get reset when an animation gets interrupted.
+     * You can use this value to provide smooth reconciliation behavior when re-targeting an
+     * animation.
+     */
+    var lastVelocity: Float by mutableFloatStateOf(0f)
+        private set
+
+    private var dragTarget: T? by mutableStateOf(null)
+
+    var anchors: DraggableAnchors<T> by mutableStateOf(emptyDraggableAnchors())
+        private set
+
+    /**
+     * Update the anchors. If there is no ongoing [anchoredDrag] operation, snap to the [newTarget],
+     * otherwise restart the ongoing [anchoredDrag] operation (e.g. an animation) with the new
+     * anchors.
+     *
+     * <b>If your anchors depend on the size of the layout, updateAnchors should be called in the
+     * layout (placement) phase, e.g. through Modifier.onSizeChanged.</b> This ensures that the
+     * state is set up within the same frame.
+     * For static anchors, or anchors with different data dependencies, [updateAnchors] is safe to
+     * be called from side effects or layout.
+     *
+     * @param newAnchors The new anchors.
+     * @param newTarget The new target, by default the closest anchor or the current target if there
+     * are no anchors.
+     */
+    fun updateAnchors(
+        newAnchors: DraggableAnchors<T>,
+        newTarget: T = if (!offset.isNaN()) {
+            newAnchors.closestAnchor(offset) ?: targetValue
+        } else targetValue
+    ) {
+        if (anchors != newAnchors) {
+            anchors = newAnchors
+            // Attempt to snap. If nobody is holding the lock, we can immediately update the offset.
+            // If anybody is holding the lock, we send a signal to restart the ongoing work with the
+            // updated anchors.
+            val snapSuccessful = trySnapTo(newTarget)
+            if (!snapSuccessful) {
+                dragTarget = newTarget
+            }
+        }
+    }
+
+    /**
+     * Find the closest anchor, taking into account the [velocityThreshold] and
+     * [positionalThreshold], and settle at it with an animation.
+     *
+     * If the [velocity] is lower than the [velocityThreshold], the closest anchor by distance and
+     * [positionalThreshold] will be the target. If the [velocity] is higher than the
+     * [velocityThreshold], the [positionalThreshold] will <b>not</b> be considered and the next
+     * anchor in the direction indicated by the sign of the [velocity] will be the target.
+     */
+    suspend fun settle(velocity: Float) {
+        val previousValue = this.currentValue
+        val targetValue = computeTarget(
+            offset = requireOffset(),
+            currentValue = previousValue,
+            velocity = velocity
+        )
+        if (confirmValueChange(targetValue)) {
+            animateTo(targetValue, velocity)
+        } else {
+            // If the user vetoed the state change, rollback to the previous state.
+            animateTo(previousValue, velocity)
+        }
+    }
+
+    private fun computeTarget(
+        offset: Float,
+        currentValue: T,
+        velocity: Float
+    ): T {
+        val currentAnchors = anchors
+        val currentAnchorPosition = currentAnchors.positionOf(currentValue)
+        val velocityThresholdPx = velocityThreshold()
+        return if (currentAnchorPosition == offset || currentAnchorPosition.isNaN()) {
+            currentValue
+        } else if (currentAnchorPosition < offset) {
+            // Swiping from lower to upper (positive).
+            if (velocity >= velocityThresholdPx) {
+                currentAnchors.closestAnchor(offset, true)!!
+            } else {
+                val upper = currentAnchors.closestAnchor(offset, true)!!
+                val distance = abs(currentAnchors.positionOf(upper) - currentAnchorPosition)
+                val relativeThreshold = abs(positionalThreshold(distance))
+                val absoluteThreshold = abs(currentAnchorPosition + relativeThreshold)
+                if (offset < absoluteThreshold) currentValue else upper
+            }
+        } else {
+            // Swiping from upper to lower (negative).
+            if (velocity <= -velocityThresholdPx) {
+                currentAnchors.closestAnchor(offset, false)!!
+            } else {
+                val lower = currentAnchors.closestAnchor(offset, false)!!
+                val distance = abs(currentAnchorPosition - currentAnchors.positionOf(lower))
+                val relativeThreshold = abs(positionalThreshold(distance))
+                val absoluteThreshold = abs(currentAnchorPosition - relativeThreshold)
+                if (offset < 0) {
+                    // For negative offsets, larger absolute thresholds are closer to lower anchors
+                    // than smaller ones.
+                    if (abs(offset) < absoluteThreshold) currentValue else lower
+                } else {
+                    if (offset > absoluteThreshold) currentValue else lower
+                }
+            }
+        }
+    }
+
+    private fun computeTargetWithoutThresholds(
+        offset: Float,
+        currentValue: T,
+    ): T {
+        val currentAnchors = anchors
+        val currentAnchor = currentAnchors.positionOf(currentValue)
+        return if (currentAnchor == offset || currentAnchor.isNaN()) {
+            currentValue
+        } else if (currentAnchor < offset) {
+            currentAnchors.closestAnchor(offset, true) ?: currentValue
+        } else {
+            currentAnchors.closestAnchor(offset, false) ?: currentValue
+        }
+    }
+
+    private val anchoredDragScope: AnchoredDragScope = object : AnchoredDragScope {
+        override fun dragTo(newOffset: Float, lastKnownVelocity: Float) {
+            offset = newOffset
+            lastVelocity = lastKnownVelocity
+        }
+    }
+
+    /**
+     * Call this function to take control of drag logic and perform anchored drag with the latest
+     * anchors.
+     *
+     * All actions that change the [offset] of this [AnchoredDraggableState] must be performed
+     * within an [anchoredDrag] block (even if they don't call any other methods on this object)
+     * in order to guarantee that mutual exclusion is enforced.
+     *
+     * If [anchoredDrag] is called from elsewhere with the [dragPriority] higher or equal to ongoing
+     * drag, the ongoing drag will be cancelled.
+     *
+     * <b>If the [anchors] change while the [block] is being executed, it will be cancelled and
+     * re-executed with the latest anchors and target.</b> This allows you to target the correct
+     * state.
+     *
+     * @param dragPriority of the drag operation
+     * @param block perform anchored drag given the current anchor provided
+     */
+    suspend fun anchoredDrag(
+        dragPriority: MutatePriority = MutatePriority.Default,
+        block: suspend AnchoredDragScope.(anchors: DraggableAnchors<T>) -> Unit
+    ) {
+        try {
+            dragMutex.mutate(dragPriority) {
+                restartable(inputs = { anchors }) { latestAnchors ->
+                    anchoredDragScope.block(latestAnchors)
+                }
+            }
+        } finally {
+            val closest = anchors.closestAnchor(offset)
+            if (closest != null && abs(offset - anchors.positionOf(closest)) <= 0.5f) {
+                currentValue = closest
+            }
+        }
+    }
+
+    /**
+     * Call this function to take control of drag logic and perform anchored drag with the latest
+     * anchors and target.
+     *
+     * All actions that change the [offset] of this [AnchoredDraggableState] must be performed
+     * within an [anchoredDrag] block (even if they don't call any other methods on this object)
+     * in order to guarantee that mutual exclusion is enforced.
+     *
+     * This overload allows the caller to hint the target value that this [anchoredDrag] is intended
+     * to arrive to. This will set [AnchoredDraggableState.targetValue] to provided value so
+     * consumers can reflect it in their UIs.
+     *
+     * <b>If the [anchors] or [AnchoredDraggableState.targetValue] change while the [block] is being
+     * executed, it will be cancelled and re-executed with the latest anchors and target.</b> This
+     * allows you to target the correct state.
+     *
+     * If [anchoredDrag] is called from elsewhere with the [dragPriority] higher or equal to ongoing
+     * drag, the ongoing drag will be cancelled.
+     *
+     * @param targetValue hint the target value that this [anchoredDrag] is intended to arrive to
+     * @param dragPriority of the drag operation
+     * @param block perform anchored drag given the current anchor provided
+     */
+    suspend fun anchoredDrag(
+        targetValue: T,
+        dragPriority: MutatePriority = MutatePriority.Default,
+        block: suspend AnchoredDragScope.(anchors: DraggableAnchors<T>, targetValue: T) -> Unit
+    ) {
+        if (anchors.hasAnchorFor(targetValue)) {
+            try {
+                dragMutex.mutate(dragPriority) {
+                    dragTarget = targetValue
+                    restartable(
+                        inputs = { anchors to this@AnchoredDraggableState.targetValue }
+                    ) { (latestAnchors, latestTarget) ->
+                        anchoredDragScope.block(latestAnchors, latestTarget)
+                    }
+                }
+            } finally {
+                dragTarget = null
+                val closest = anchors.closestAnchor(offset)
+                if (closest != null && abs(offset - anchors.positionOf(closest)) <= 0.5f) {
+                    currentValue = closest
+                }
+            }
+        } else {
+            // Todo: b/283467401, revisit this behavior
+            currentValue = targetValue
+        }
+    }
+
+    internal fun newOffsetForDelta(delta: Float) =
+        ((if (offset.isNaN()) 0f else offset) + delta)
+            .coerceIn(anchors.minAnchor(), anchors.maxAnchor())
+
+    /**
+     * Drag by the [delta], coerce it in the bounds and dispatch it to the [AnchoredDraggableState].
+     *
+     * @return The delta the consumed by the [AnchoredDraggableState]
+     */
+    fun dispatchRawDelta(delta: Float): Float {
+        val newOffset = newOffsetForDelta(delta)
+        val oldOffset = if (offset.isNaN()) 0f else offset
+        offset = newOffset
+        return newOffset - oldOffset
+    }
+
+    /**
+     * Attempt to snap synchronously. Snapping can happen synchronously when there is no other drag
+     * transaction like a drag or an animation is progress. If there is another interaction in
+     * progress, the suspending [snapTo] overload needs to be used.
+     *
+     * @return true if the synchronous snap was successful, or false if we couldn't snap synchronous
+     */
+    private fun trySnapTo(targetValue: T): Boolean = dragMutex.tryMutate {
+        with(anchoredDragScope) {
+            val targetOffset = anchors.positionOf(targetValue)
+            if (!targetOffset.isNaN()) {
+                dragTo(targetOffset)
+                dragTarget = null
+            }
+            currentValue = targetValue
+        }
+    }
+
+    companion object {
+        /**
+         * The default [Saver] implementation for [AnchoredDraggableState].
+         */
+        @ExperimentalFoundationApi
+        fun <T : Any> Saver(
+            animationSpec: AnimationSpec<Float>,
+            @Suppress("PrimitiveInLambda")
+            positionalThreshold: (distance: Float) -> Float,
+            @Suppress("PrimitiveInLambda")
+            velocityThreshold: () -> Float,
+            confirmValueChange: (T) -> Boolean = { true },
+        ) = Saver<AnchoredDraggableState<T>, T>(
+            save = { it.currentValue },
+            restore = {
+                AnchoredDraggableState(
+                    initialValue = it,
+                    animationSpec = animationSpec,
+                    confirmValueChange = confirmValueChange,
+                    positionalThreshold = positionalThreshold,
+                    velocityThreshold = velocityThreshold
+                )
+            }
+        )
+    }
+}
+
+/**
+ * Snap to a [targetValue] without any animation.
+ * If the [targetValue] is not in the set of anchors, the [AnchoredDraggableState.currentValue] will
+ * be updated to the [targetValue] without updating the offset.
+ *
+ * @throws CancellationException if the interaction interrupted by another interaction like a
+ * gesture interaction or another programmatic interaction like a [animateTo] or [snapTo] call.
+ *
+ * @param targetValue The target value of the animation
+ */
+@ExperimentalFoundationApi
+suspend fun <T> AnchoredDraggableState<T>.snapTo(targetValue: T) {
+    anchoredDrag(targetValue = targetValue) { anchors, latestTarget ->
+        val targetOffset = anchors.positionOf(latestTarget)
+        if (!targetOffset.isNaN()) dragTo(targetOffset)
+    }
+}
+
+/**
+ * Animate to a [targetValue].
+ * If the [targetValue] is not in the set of anchors, the [AnchoredDraggableState.currentValue] will
+ * be updated to the [targetValue] without updating the offset.
+ *
+ * @throws CancellationException if the interaction interrupted by another interaction like a
+ * gesture interaction or another programmatic interaction like a [animateTo] or [snapTo] call.
+ *
+ * @param targetValue The target value of the animation
+ * @param velocity The velocity the animation should start with
+ */
+@ExperimentalFoundationApi
+suspend fun <T> AnchoredDraggableState<T>.animateTo(
+    targetValue: T,
+    velocity: Float = this.lastVelocity,
+) {
+    anchoredDrag(targetValue = targetValue) { anchors, latestTarget ->
+        val targetOffset = anchors.positionOf(latestTarget)
+        if (!targetOffset.isNaN()) {
+            var prev = if (offset.isNaN()) 0f else offset
+            animate(prev, targetOffset, velocity, animationSpec) { value, velocity ->
+                // Our onDrag coerces the value within the bounds, but an animation may
+                // overshoot, for example a spring animation or an overshooting interpolator
+                // We respect the user's intention and allow the overshoot, but still use
+                // DraggableState's drag for its mutex.
+                dragTo(value, velocity)
+                prev = value
+            }
+        }
+    }
+}
+
+private class AnchoredDragFinishedSignal : CancellationException() {
+    override fun fillInStackTrace(): Throwable {
+        stackTrace = emptyArray()
+        return this
+    }
+}
+
+private suspend fun <I> restartable(inputs: () -> I, block: suspend (I) -> Unit) {
+    try {
+        coroutineScope {
+            var previousDrag: Job? = null
+            snapshotFlow(inputs)
+                .collect { latestInputs ->
+                    previousDrag?.apply {
+                        cancel(AnchoredDragFinishedSignal())
+                        join()
+                    }
+                    previousDrag = launch(start = CoroutineStart.UNDISPATCHED) {
+                        block(latestInputs)
+                        this@coroutineScope.cancel(AnchoredDragFinishedSignal())
+                    }
+                }
+        }
+    } catch (anchoredDragFinished: AnchoredDragFinishedSignal) {
+        // Ignored
+    }
+}
+
+private fun <T> emptyDraggableAnchors() = MapDraggableAnchors<T>(emptyMap())
+
+@OptIn(ExperimentalFoundationApi::class)
+private class MapDraggableAnchors<T>(private val anchors: Map<T, Float>) : DraggableAnchors<T> {
+
+    override fun positionOf(value: T): Float = anchors[value] ?: Float.NaN
+    override fun hasAnchorFor(value: T) = anchors.containsKey(value)
+
+    override fun closestAnchor(position: Float): T? = anchors.minByOrNull {
+        abs(position - it.value)
+    }?.key
+
+    override fun closestAnchor(
+        position: Float,
+        searchUpwards: Boolean
+    ): T? {
+        return anchors.minByOrNull { (_, anchor) ->
+            val delta = if (searchUpwards) anchor - position else position - anchor
+            if (delta < 0) Float.POSITIVE_INFINITY else delta
+        }?.key
+    }
+
+    override fun minAnchor() = anchors.values.minOrNull() ?: Float.NaN
+
+    override fun maxAnchor() = anchors.values.maxOrNull() ?: Float.NaN
+
+    override val size: Int
+        get() = anchors.size
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is MapDraggableAnchors<*>) return false
+
+        return anchors == other.anchors
+    }
+
+    override fun hashCode() = 31 * anchors.hashCode()
+
+    override fun toString() = "MapDraggableAnchors($anchors)"
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue.kt
index 3507443..6f023af 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/BringIntoViewRequestPriorityQueue.kt
@@ -132,6 +132,6 @@
         requests.map { it.continuation }.forEach {
             it.cancel(cause)
         }
-        check(requests.isEmpty())
+        check(requests.isEmpty()) { "uncancelled requests present" }
     }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
index 1efe022..d564e17 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/ContentInViewNode.kt
@@ -175,7 +175,7 @@
     }
 
     private fun launchAnimation() {
-        check(!isAnimationRunning)
+        check(!isAnimationRunning) { "launchAnimation called when previous animation was running" }
 
         if (DEBUG) println("[$TAG] launchAnimation")
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
index a7ef52a..177e729 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/UpdatableAnimationState.kt
@@ -89,7 +89,7 @@
         afterFrame: () -> Unit,
     ) {
         contract { callsInPlace(beforeFrame) }
-        check(!isRunning)
+        check(!isRunning) { "animateToZero called while previous animation is running" }
 
         val durationScale = coroutineContext[MotionDurationScale]?.scaleFactor ?: 1f
         isRunning = true
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
index 27b1d40..6f41836 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
@@ -229,9 +229,13 @@
         )
 
         val spaceBetweenItemsDp = if (isVertical) {
-            requireNotNull(verticalArrangement).spacing
+            requireNotNull(verticalArrangement) {
+                "null verticalArrangement when isVertical == true"
+            }.spacing
         } else {
-            requireNotNull(horizontalArrangement).spacing
+            requireNotNull(horizontalArrangement) {
+                "null horizontalAlignment when isVertical == false"
+            }.spacing
         }
         val spaceBetweenItems = spaceBetweenItemsDp.roundToPx()
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
index 9a30e6b..a352409 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
@@ -60,8 +60,8 @@
     @Suppress("PrimitiveInLambda")
     layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
 ): LazyListMeasureResult {
-    require(beforeContentPadding >= 0)
-    require(afterContentPadding >= 0)
+    require(beforeContentPadding >= 0) { "invalid beforeContentPadding" }
+    require(afterContentPadding >= 0) { "invalid afterContentPadding" }
     if (itemsCount <= 0) {
         // empty data set. reset the current scroll and report zero size
         return LazyListMeasureResult(
@@ -209,7 +209,7 @@
         }
 
         // the initial offset for items from visibleItems list
-        require(currentFirstItemScrollOffset >= 0)
+        require(currentFirstItemScrollOffset >= 0) { "negative currentFirstItemScrollOffset" }
         val visibleItemsScrollOffset = -currentFirstItemScrollOffset
         var firstItem = visibleItems.first()
 
@@ -408,14 +408,14 @@
     val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
     val hasSpareSpace = finalMainAxisOffset < minOf(mainAxisLayoutSize, maxOffset)
     if (hasSpareSpace) {
-        check(itemsScrollOffset == 0)
+        check(itemsScrollOffset == 0) { "non-zero itemsScrollOffset" }
     }
 
     val positionedItems =
         ArrayList<LazyListMeasuredItem>(items.size + extraItemsBefore.size + extraItemsAfter.size)
 
     if (hasSpareSpace) {
-        require(extraItemsBefore.isEmpty() && extraItemsAfter.isEmpty())
+        require(extraItemsBefore.isEmpty() && extraItemsAfter.isEmpty()) { "no extra items" }
 
         val itemsCount = items.size
         fun Int.reverseAware() =
@@ -426,11 +426,19 @@
         }
         val offsets = IntArray(itemsCount) { 0 }
         if (isVertical) {
-            with(requireNotNull(verticalArrangement)) {
+            with(
+                requireNotNull(verticalArrangement) {
+                    "null verticalArrangement when isVertical == true"
+                }
+            ) {
                 density.arrange(mainAxisLayoutSize, sizes, offsets)
             }
         } else {
-            with(requireNotNull(horizontalArrangement)) {
+            with(
+                requireNotNull(horizontalArrangement) {
+                    "null horizontalArrangement when isVertical == false"
+                }
+            ) {
                 // Enforces Ltr layout direction as it is mirrored with placeRelative later.
                 density.arrange(mainAxisLayoutSize, sizes, LayoutDirection.Ltr, offsets)
             }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
index 5fb7dc9..b7993d7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
@@ -110,14 +110,18 @@
         placeables.fastForEachIndexed { index, placeable ->
             val indexInArray = index * 2
             if (isVertical) {
-                placeableOffsets[indexInArray] = requireNotNull(horizontalAlignment)
-                    .align(placeable.width, layoutWidth, layoutDirection)
+                placeableOffsets[indexInArray] =
+                    requireNotNull(horizontalAlignment) {
+                        "null horizontalAlignment when isVertical == true"
+                    }.align(placeable.width, layoutWidth, layoutDirection)
                 placeableOffsets[indexInArray + 1] = mainAxisOffset
                 mainAxisOffset += placeable.height
             } else {
                 placeableOffsets[indexInArray] = mainAxisOffset
-                placeableOffsets[indexInArray + 1] = requireNotNull(verticalAlignment)
-                    .align(placeable.height, layoutHeight)
+                placeableOffsets[indexInArray + 1] =
+                    requireNotNull(verticalAlignment) {
+                        "null verticalAlignment when isVertical == false"
+                    }.align(placeable.height, layoutHeight)
                 mainAxisOffset += placeable.width
             }
         }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
index 385b153..ff95f02 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
@@ -228,9 +228,13 @@
         state.slotsPerLine = slotsPerLine
 
         val spaceBetweenLinesDp = if (isVertical) {
-            requireNotNull(verticalArrangement).spacing
+            requireNotNull(verticalArrangement) {
+                "null verticalArrangement when isVertical == true"
+            }.spacing
         } else {
-            requireNotNull(horizontalArrangement).spacing
+            requireNotNull(horizontalArrangement) {
+                "null horizontalArrangement when isVertical == false"
+            }.spacing
         }
         val spaceBetweenLines = spaceBetweenLinesDp.roundToPx()
         val itemsCount = itemProvider.itemCount
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
index c9cebf8..0f95dd1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
@@ -62,8 +62,8 @@
     @Suppress("PrimitiveInLambda")
     layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
 ): LazyGridMeasureResult {
-    require(beforeContentPadding >= 0)
-    require(afterContentPadding >= 0)
+    require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
+    require(afterContentPadding >= 0) { "negative afterContentPadding" }
     if (itemsCount <= 0) {
         // empty data set. reset the current scroll and report zero size
         return LazyGridMeasureResult(
@@ -202,7 +202,7 @@
         }
 
         // the initial offset for lines from visibleLines list
-        require(currentFirstLineScrollOffset >= 0)
+        require(currentFirstLineScrollOffset >= 0) { "negative initial offset" }
         val visibleLinesScrollOffset = -currentFirstLineScrollOffset
         var firstLine = visibleLines.first()
 
@@ -348,13 +348,13 @@
     val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
     val hasSpareSpace = finalMainAxisOffset < min(mainAxisLayoutSize, maxOffset)
     if (hasSpareSpace) {
-        check(firstLineScrollOffset == 0)
+        check(firstLineScrollOffset == 0) { "non-zero firstLineScrollOffset" }
     }
 
     val positionedItems = ArrayList<LazyGridMeasuredItem>(lines.fastSumBy { it.items.size })
 
     if (hasSpareSpace) {
-        require(itemsBefore.isEmpty() && itemsAfter.isEmpty())
+        require(itemsBefore.isEmpty() && itemsAfter.isEmpty()) { "no items" }
         val linesCount = lines.size
         fun Int.reverseAware() =
             if (!reverseLayout) this else linesCount - this - 1
@@ -364,11 +364,11 @@
         }
         val offsets = IntArray(linesCount) { 0 }
         if (isVertical) {
-            with(requireNotNull(verticalArrangement)) {
+            with(requireNotNull(verticalArrangement) { "null verticalArrangement" }) {
                 density.arrange(mainAxisLayoutSize, sizes, offsets)
             }
         } else {
-            with(requireNotNull(horizontalArrangement)) {
+            with(requireNotNull(horizontalArrangement) { "null horizontalArrangement" }) {
                 // Enforces Ltr layout direction as it is mirrored with placeRelative later.
                 density.arrange(mainAxisLayoutSize, sizes, LayoutDirection.Ltr, offsets)
             }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
index 05be19d..9237016 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItemProvider.kt
@@ -46,7 +46,7 @@
         val crossAxisSize = if (constraints.hasFixedWidth) {
             constraints.minWidth
         } else {
-            require(constraints.hasFixedHeight)
+            require(constraints.hasFixedHeight) { "does not have fixed height" }
             constraints.minHeight
         }
         return createItem(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
index ac6ac2a..d72d099 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
@@ -110,7 +110,7 @@
             cachedBucket.clear()
         }
 
-        check(currentLine <= lineIndex)
+        check(currentLine <= lineIndex) { "currentLine > lineIndex" }
 
         while (currentLine < lineIndex && currentItemIndex < totalSize) {
             if (cacheThisBucket) {
@@ -136,7 +136,7 @@
             if (currentLine % bucketSize == 0 && currentItemIndex < totalSize) {
                 val currentLineBucket = currentLine / bucketSize
                 // This should happen, as otherwise this should have been used as starting point.
-                check(buckets.size == currentLineBucket)
+                check(buckets.size == currentLineBucket) { "invalid starting point" }
                 buckets.add(Bucket(currentItemIndex, knownCurrentItemSpan))
             }
         }
@@ -171,7 +171,7 @@
         if (totalSize <= 0) {
             return 0
         }
-        require(itemIndex < totalSize)
+        require(itemIndex < totalSize) { "ItemIndex > total count" }
         if (!gridContent.hasCustomSpans) {
             return itemIndex / slotsPerLine
         }
@@ -182,7 +182,7 @@
         var currentLine = lowerBoundBucket * bucketSize
         var currentItemIndex = buckets[lowerBoundBucket].firstItemIndex
 
-        require(currentItemIndex <= itemIndex)
+        require(currentItemIndex <= itemIndex) { "currentItemIndex > itemIndex" }
         var spansUsed = 0
         while (currentItemIndex < itemIndex) {
             val span = spanOf(currentItemIndex++, slotsPerLine - spansUsed)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo.kt
index 34d2918..7403fb2 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutBeyondBoundsInfo.kt
@@ -89,7 +89,7 @@
                     minIndex = it.start
                 }
             }
-            require(minIndex >= 0)
+            require(minIndex >= 0) { "negative minIndex" }
             return minIndex
         }
 
@@ -118,8 +118,8 @@
         val end: Int
     ) {
         init {
-            require(start >= 0)
-            require(end >= start)
+            require(start >= 0) { "negative start index" }
+            require(end >= start) { "end index greater than start" }
         }
     }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
index 50393c9..d0c2794 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
@@ -63,7 +63,7 @@
         // all the indexes in the passed [range].
         val list = intervalContent.intervals
         val first = nearestRange.first
-        check(first >= 0)
+        check(first >= 0) { "negative nearestRange.first" }
         val last = minOf(nearestRange.last, list.size - 1)
         if (last < first) {
             map = emptyMap()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazySaveableStateHolder.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazySaveableStateHolder.kt
index f13bf2c..c4c4a75 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazySaveableStateHolder.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazySaveableStateHolder.kt
@@ -81,7 +81,8 @@
 
     @Composable
     override fun SaveableStateProvider(key: Any, content: @Composable () -> Unit) {
-        requireNotNull(wrappedHolder).SaveableStateProvider(key, content)
+        requireNotNull(wrappedHolder) { "null wrappedHolder" }
+            .SaveableStateProvider(key, content)
         DisposableEffect(key) {
             previouslyComposedKeys -= key
             onDispose {
@@ -91,7 +92,8 @@
     }
 
     override fun removeState(key: Any) {
-        requireNotNull(wrappedHolder).removeState(key)
+        requireNotNull(wrappedHolder) { "null wrappedHolder" }
+            .removeState(key)
     }
 
     companion object {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridCells.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridCells.kt
index c9c1eb9..d401085 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridCells.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridCells.kt
@@ -54,7 +54,7 @@
      */
     class Fixed(private val count: Int) : StaggeredGridCells {
         init {
-            require(count > 0)
+            require(count > 0) { "grid with no rows/columns" }
         }
 
         override fun Density.calculateCrossAxisCellSizes(
@@ -84,7 +84,7 @@
      */
     class Adaptive(private val minSize: Dp) : StaggeredGridCells {
         init {
-            require(minSize > 0.dp)
+            require(minSize > 0.dp) { "invalid minSize" }
         }
 
         override fun Density.calculateCrossAxisCellSizes(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
index 8ad0a3e..45748d4 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/MeasuredPage.kt
@@ -76,13 +76,15 @@
         placeables.fastForEachIndexed { index, placeable ->
             val indexInArray = index * 2
             if (isVertical) {
-                placeableOffsets[indexInArray] = requireNotNull(horizontalAlignment)
+                placeableOffsets[indexInArray] =
+                    requireNotNull(horizontalAlignment) { "null horizontalAlignment" }
                     .align(placeable.width, layoutWidth, layoutDirection)
                 placeableOffsets[indexInArray + 1] = mainAxisOffset
                 mainAxisOffset += placeable.height
             } else {
                 placeableOffsets[indexInArray] = mainAxisOffset
-                placeableOffsets[indexInArray + 1] = requireNotNull(verticalAlignment)
+                placeableOffsets[indexInArray + 1] =
+                    requireNotNull(verticalAlignment) { "null verticalAlignment" }
                     .align(placeable.height, layoutHeight)
                 mainAxisOffset += placeable.width
             }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
index 4947349..787d64b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/pager/PagerMeasure.kt
@@ -60,8 +60,8 @@
     @Suppress("PrimitiveInLambda")
     layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
 ): PagerMeasureResult {
-    require(beforeContentPadding >= 0)
-    require(afterContentPadding >= 0)
+    require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
+    require(afterContentPadding >= 0) { "negative afterContentPadding" }
     val pageSizeWithSpacing = (pageAvailableSize + spaceBetweenPages).coerceAtLeast(0)
     debugLog { "Remeasuring..." }
     return if (pageCount <= 0) {
@@ -265,7 +265,7 @@
         }
 
         // the initial offset for pages from visiblePages list
-        require(currentFirstPageScrollOffset >= 0)
+        require(currentFirstPageScrollOffset >= 0) { "invalid currentFirstPageScrollOffset" }
         val visiblePagesScrollOffset = -currentFirstPageScrollOffset
         var firstPage = visiblePages.first()
 
@@ -518,13 +518,13 @@
     val mainAxisLayoutSize = if (orientation == Orientation.Vertical) layoutHeight else layoutWidth
     val hasSpareSpace = finalMainAxisOffset < minOf(mainAxisLayoutSize, maxOffset)
     if (hasSpareSpace) {
-        check(pagesScrollOffset == 0)
+        check(pagesScrollOffset == 0) { "non-zero pagesScrollOffset" }
     }
     val positionedPages =
         ArrayList<MeasuredPage>(pages.size + extraPagesBefore.size + extraPagesAfter.size)
 
     if (hasSpareSpace) {
-        require(extraPagesBefore.isEmpty() && extraPagesAfter.isEmpty())
+        require(extraPagesBefore.isEmpty() && extraPagesAfter.isEmpty()) { "No extra pages" }
 
         val pagesCount = pages.size
         fun Int.reverseAware() =
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextDelegate.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextDelegate.kt
index d0ef6f0..837b118 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextDelegate.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextDelegate.kt
@@ -121,9 +121,9 @@
     val maxIntrinsicWidth: Int get() = nonNullIntrinsics.maxIntrinsicWidth.ceilToIntPx()
 
     init {
-        check(maxLines > 0)
-        check(minLines > 0)
-        check(minLines <= maxLines)
+        require(maxLines > 0) { "no maxLines" }
+        require(minLines > 0) { "no minLines" }
+        require(minLines <= maxLines) { "minLines greater than maxLines" }
     }
 
     fun layoutIntrinsics(layoutDirection: LayoutDirection) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
index 4831670..2d39051 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/TextStringSimpleNode.kt
@@ -388,7 +388,7 @@
      * Optimized Text draw.
      */
     override fun ContentDrawScope.draw() {
-        val localParagraph = requireNotNull(layoutCache.paragraph)
+        val localParagraph = requireNotNull(layoutCache.paragraph) { "no paragraph" }
         drawIntoCanvas { canvas ->
             val willClip = layoutCache.didOverflow
             if (willClip) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
index bb0671b..62e6c4b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
@@ -371,8 +371,8 @@
      */
     internal fun requireContainerCoordinates(): LayoutCoordinates {
         val coordinates = containerLayoutCoordinates
-        require(coordinates != null)
-        require(coordinates.isAttached)
+        requireNotNull(coordinates) { "null coordinates" }
+        require(coordinates.isAttached) { "unattached coordinates" }
         return coordinates
     }
 
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/MutatorMutexTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/MutatorMutexTest.kt
index b5ade04..4d6588d 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/MutatorMutexTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/MutatorMutexTest.kt
@@ -18,10 +18,12 @@
 
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.suspendCancellableCoroutine
+import org.junit.Assert
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertSame
 import org.junit.Assert.assertTrue
@@ -83,6 +85,83 @@
         runMutatorsCancelByPriority(MutateWithReceiverCaller(mutex))
     }
 
+    @Test
+    fun tryMutateBlockingSuspendsSubsequentMutate() = runBlocking<Unit> {
+        val mutex = MutatorMutex()
+        val tryMutateJob = launch(start = CoroutineStart.LAZY) {
+            mutex.tryMutate {
+                while (true) { /* Block forever */ }
+            }
+        }
+        val mutateJob = launch(start = CoroutineStart.LAZY) {
+            mutex.mutate {
+                if (tryMutateJob.isActive) fail("Attempted to mutate before tryMutate finished")
+            }
+        }
+        tryMutateJob.start()
+        mutateJob.start()
+
+        tryMutateJob.cancelAndJoin()
+        mutateJob.cancelAndJoin()
+    }
+
+    @Test
+    fun tryMutateDoesNotOverrideActiveCaller() = runBlocking<Unit> {
+        val mutex = MutatorMutex()
+        val mutateJob = launch(start = CoroutineStart.UNDISPATCHED) {
+            mutex.mutate {
+                suspendCancellableCoroutine { } // Suspend forever
+            }
+        }
+        val tryMutateSuccessful = mutex.tryMutate { }
+        Assert.assertFalse(
+            "tryMutate should not run if there is an ongoing mutation",
+            tryMutateSuccessful
+        )
+        mutateJob.cancelAndJoin()
+    }
+
+    @Test
+    fun tryMutateBlockingTryMutateLocks() = runBlocking<Unit> {
+        val mutex = MutatorMutex()
+        mutex.tryMutate {
+            val tryMutateSuccessful = mutex.tryMutate { }
+            Assert.assertFalse(
+                "tryMutate should not run if there is an ongoing mutation",
+                tryMutateSuccessful
+            )
+        }
+    }
+
+    @Test
+    fun tryLockUnlockedMutexLocks() {
+        val mutex = MutatorMutex()
+        val didLock = mutex.tryLock()
+        assertTrue("The mutex was not locked", didLock)
+    }
+
+    @Test
+    fun tryLockLockedMutexDoesNotLock() {
+        val mutex = MutatorMutex()
+        val didLockInitially = mutex.tryLock()
+        assertTrue("The mutex was not locked", didLockInitially)
+
+        val didLockAfterFirstLock = mutex.tryLock()
+        Assert.assertFalse("The mutex was locked", didLockAfterFirstLock)
+    }
+
+    @Test
+    fun unlockLockedMutex() {
+        val mutex = MutatorMutex()
+        val didLockInitially = mutex.tryLock()
+        assertTrue("The mutex was not locked", didLockInitially)
+
+        mutex.unlock()
+        // The mutex should lock again after being unlocked
+        val didLockAfterUnlock = mutex.tryLock()
+        assertTrue("The mutex was not locked", didLockAfterUnlock)
+    }
+
     private suspend fun runMutatorsCancelByPriority(mutex: MutateCaller) = coroutineScope<Unit> {
         for (firstPriority in MutatePriority.values()) {
             for (secondPriority in MutatePriority.values()) {
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt
new file mode 100644
index 0000000..cc2bba3
--- /dev/null
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DraggableAnchorsTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package androidx.compose.foundation.gestures
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.TestValue.A
+import androidx.compose.foundation.gestures.TestValue.B
+import androidx.compose.foundation.gestures.TestValue.C
+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 DraggableAnchorsTest {
+
+    @Test
+    fun draggableAnchors_builder_containsAll() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+            C at 200f
+        }
+        assertThat(anchors.positionOf(A)).isEqualTo(0f)
+        assertThat(anchors.positionOf(B)).isEqualTo(100f)
+        assertThat(anchors.positionOf(C)).isEqualTo(200f)
+    }
+
+    @Test
+    fun draggableAnchors_get_nonexistentAnchor_returnsNaN() {
+        val anchors = DraggableAnchors<TestValue> { }
+        assertThat(anchors.positionOf(A)).isNaN()
+    }
+
+    @Test
+    fun draggableAnchors_findsClosestAnchor() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+            C at 200f
+        }
+        assertThat(anchors.closestAnchor(25f)).isEqualTo(A)
+        assertThat(anchors.closestAnchor(75f)).isEqualTo(B)
+        assertThat(anchors.closestAnchor(175f)).isEqualTo(C)
+    }
+
+    @Test
+    fun draggableAnchors_findsClosestAnchor_directional() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+        }
+        assertThat(anchors.closestAnchor(1f, searchUpwards = true)).isEqualTo(B)
+        assertThat(anchors.closestAnchor(99f, searchUpwards = false)).isEqualTo(A)
+    }
+
+    @Test
+    fun draggableAnchors_minAnchor() {
+        val anchors = DraggableAnchors {
+            A at -100f
+            B at 100f
+        }
+        assertThat(anchors.minAnchor()).isEqualTo(-100f)
+    }
+
+    @Test
+    fun draggableAnchors_maxAnchor() {
+        val anchors = DraggableAnchors {
+            A at -100f
+            B at 100f
+        }
+        assertThat(anchors.maxAnchor()).isEqualTo(100f)
+    }
+
+    @Test
+    fun draggableAnchors_hasAnchorFor() {
+        val anchors = DraggableAnchors {
+            A at 100f
+        }
+        assertThat(anchors.positionOf(A)).isEqualTo(100f)
+        assertThat(anchors.hasAnchorFor(A)).isTrue()
+    }
+}
+
+private enum class TestValue { A, B, C }
\ No newline at end of file
diff --git a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
index d891805..c409211 100644
--- a/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
+++ b/compose/integration-tests/demos/src/main/java/androidx/compose/integration/demos/DemoActivity.kt
@@ -237,9 +237,9 @@
                 (navigator.backStack + navigator.currentDemo).map { it.title }
             },
             restore = { restored ->
-                require(restored.isNotEmpty())
+                require(restored.isNotEmpty()) { "no restored items" }
                 val backStack = restored.mapTo(mutableListOf()) {
-                    requireNotNull(findDemo(rootDemo, it, exact = true))
+                    requireNotNull(findDemo(rootDemo, it, exact = true)) { "no root demo" }
                 }
                 val initial = backStack.removeAt(backStack.lastIndex)
                 Navigator(backDispatcher, launchActivityDemo, rootDemo, initial, backStack)
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
index 57c0bf9..223ceaf 100644
--- a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ComposeIssueRegistry.kt
@@ -28,6 +28,7 @@
     override val api = 14
     override val issues get(): List<Issue> {
         return listOf(
+            ExceptionMessageDetector.ISSUE,
             ListIteratorDetector.ISSUE,
             SteppedForLoopDetector.ISSUE,
             UnnecessaryLambdaCreationDetector.ISSUE,
diff --git a/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ExceptionMessageDetector.kt b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ExceptionMessageDetector.kt
new file mode 100644
index 0000000..232a309
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/main/java/androidx/compose/lint/ExceptionMessageDetector.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import java.util.EnumSet
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.getParameterForArgument
+
+class ExceptionMessageDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> =
+        listOf(Check, CheckNotNull, Require, RequireNotNull).map { it.shortName }
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+
+        // We ignore other functions with the same name.
+        if (!method.isInPackageName(KotlinPackage)) return
+
+        val lazyMessage = node.valueArguments
+            .find { node.getParameterForArgument(it)?.name == "lazyMessage" }
+        if (lazyMessage == null) {
+            context.report(
+                ISSUE,
+                node,
+                context.getNameLocation(node),
+                "Please specify a lazyMessage param for ${node.methodName}",
+            )
+        }
+    }
+
+    companion object {
+        val KotlinPackage = Package("kotlin")
+        val Check = Name(KotlinPackage, "check")
+        val CheckNotNull = Name(KotlinPackage, "checkNotNull")
+        val Require = Name(KotlinPackage, "require")
+        val RequireNotNull = Name(KotlinPackage, "requireNotNull")
+        val ISSUE = Issue.create(
+            id = "ExceptionMessage",
+            briefDescription = "Please provide a string for the lazyMessage parameter",
+            explanation = """
+                Calls to check(), checkNotNull(), require() and requireNotNull() should
+                include a message string that can be used to debug issues experienced
+                by users.
+
+                When we read user-supplied logs, the line numbers are sometimes not
+                sufficient to determine the cause of a bug. Inline functions can
+                sometimes make it hard to determine which file threw an exception.
+                Consider supplying a lazyMessage parameter to identify the check()
+                or require() call.
+            """,
+            category = Category.CORRECTNESS,
+            priority = 3,
+            severity = Severity.ERROR,
+            implementation = Implementation(
+                ExceptionMessageDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE)
+            )
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ExceptionMessageDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ExceptionMessageDetectorTest.kt
new file mode 100644
index 0000000..cf2d8176
--- /dev/null
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/ExceptionMessageDetectorTest.kt
@@ -0,0 +1,573 @@
+/*
+ * 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.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExceptionMessageDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = ExceptionMessageDetector()
+
+    override fun getIssues(): MutableList<Issue> {
+        return mutableListOf(ExceptionMessageDetector.ISSUE)
+    }
+
+    @Test
+    fun checkWithMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(true) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkWithNamedParameterValue() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(value = true) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkWithNamedParameterMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(true, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkWithNamedParameterValueAndMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(value = true, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkWithNamedParameterValueAndMessageReversed() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(lazyMessage = {"Message"}, value = true)
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(true)
+                    }
+                    """
+                ),
+            )
+            .run()
+            .expect(
+                """
+                    src/test/test.kt:5: Error: Please specify a lazyMessage param for check [ExceptionMessage]
+                                            check(true)
+                                            ~~~~~
+                    1 errors, 0 warnings
+                """
+            )
+    }
+
+    @Test
+    fun checkFromDifferentPackageWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        check(true)
+                    }
+
+                    fun check(boolean: Boolean) {}
+                    """
+                ),
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(null) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithNamedParameterValue() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(value = null) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithNamedParameterMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(null, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithNamedParameterValueAndMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(value = null, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithNamedParameterValueAndMessageReversed() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(lazyMessage = {"Message"}, value = null)
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun checkNotNullWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(null)
+                    }
+                    """
+                ),
+            )
+            .run()
+            .expect(
+                """
+                    src/test/test.kt:5: Error: Please specify a lazyMessage param for checkNotNull [ExceptionMessage]
+                                            checkNotNull(null)
+                                            ~~~~~~~~~~~~
+                    1 errors, 0 warnings
+                """
+            )
+    }
+
+    @Test
+    fun checkNotNullFromDifferentPackageWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        checkNotNull(null)
+                    }
+
+                    fun checkNotNull(value: Any?) {}
+                    """
+                ),
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(true) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithNamedParameterValue() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(value = true) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithNamedParameterMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(true, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithNamedParameterValueAndMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(value = true, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithNamedParameterValueAndMessageReversed() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(lazyMessage = {"Message"}, value = true)
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(true)
+                    }
+                    """
+                ),
+            )
+            .run()
+            .expect(
+                """
+                    src/test/test.kt:5: Error: Please specify a lazyMessage param for require [ExceptionMessage]
+                                            require(true)
+                                            ~~~~~~~
+                    1 errors, 0 warnings
+                """
+            )
+    }
+
+    @Test
+    fun requireFromDifferentPackageWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        require(true)
+                    }
+
+                    fun require(boolean: Boolean) {}
+                    """
+                ),
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(null) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithNamedParameterValue() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(value = null) {"Message"}
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithNamedParameterMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(null, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithNamedParameterValueAndMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(value = null, lazyMessage = {"Message"})
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithNamedParameterValueAndMessageReversed() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(lazyMessage = {"Message"}, value = null)
+                    }
+                    """
+                )
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun requireNotNullWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(null)
+                    }
+                    """
+                ),
+            )
+            .run()
+            .expect(
+                """
+                    src/test/test.kt:5: Error: Please specify a lazyMessage param for requireNotNull [ExceptionMessage]
+                                            requireNotNull(null)
+                                            ~~~~~~~~~~~~~~
+                    1 errors, 0 warnings
+                """
+            )
+    }
+
+    @Test
+    fun requireNotNullFromDifferentPackageWithoutMessage() {
+        lint()
+            .files(
+                kotlin(
+                    """
+                    package test
+
+                    fun content() {
+                        requireNotNull(null)
+                    }
+
+                    fun requireNotNull(value: Any?) {}
+                    """
+                ),
+            )
+            .run()
+            .expectClean()
+    }
+}
\ No newline at end of file
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index f364bc2..c8319a15 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -457,10 +457,10 @@
     property public final int End;
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
-    ctor public FixedThreshold(float offset);
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
+    ctor @Deprecated public FixedThreshold(float offset);
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+    method @Deprecated public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
   }
 
   public final class FloatingActionButtonDefaults {
@@ -478,10 +478,10 @@
     method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
-    ctor public FractionalThreshold(float fraction);
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.compose.material.FractionalThreshold copy(float fraction);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
+    ctor @Deprecated public FractionalThreshold(float fraction);
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+    method @Deprecated public androidx.compose.material.FractionalThreshold copy(float fraction);
   }
 
   public final class IconButtonKt {
@@ -625,15 +625,15 @@
     method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.RadioButtonColors colors);
   }
 
-  @androidx.compose.runtime.Immutable public final class ResistanceConfig {
-    ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
-    method public float computeResistance(float overflow);
-    method public float getBasis();
-    method public float getFactorAtMax();
-    method public float getFactorAtMin();
-    property public final float basis;
-    property public final float factorAtMax;
-    property public final float factorAtMin;
+  @Deprecated @androidx.compose.runtime.Immutable public final class ResistanceConfig {
+    ctor @Deprecated public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+    method @Deprecated public float computeResistance(float overflow);
+    method @Deprecated public float getBasis();
+    method @Deprecated public float getFactorAtMax();
+    method @Deprecated public float getFactorAtMin();
+    property @Deprecated public final float basis;
+    property @Deprecated public final float factorAtMax;
+    property @Deprecated public final float factorAtMin;
   }
 
   public final class ScaffoldKt {
@@ -745,14 +745,14 @@
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional androidx.compose.foundation.BorderStroke? border, optional float elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class SwipeProgress<T> {
-    ctor public SwipeProgress(T from, T to, float fraction);
-    method public float getFraction();
-    method public T getFrom();
-    method public T getTo();
-    property public final float fraction;
-    property public final T from;
-    property public final T to;
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class SwipeProgress<T> {
+    ctor @Deprecated public SwipeProgress(T from, T to, float fraction);
+    method @Deprecated public float getFraction();
+    method @Deprecated public T getFrom();
+    method @Deprecated public T getTo();
+    property @Deprecated public final float fraction;
+    property @Deprecated public final T from;
+    property @Deprecated public final T to;
   }
 
   public final class SwipeToDismissKt {
@@ -760,47 +760,47 @@
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.DismissState rememberDismissState(optional androidx.compose.material.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissValue,java.lang.Boolean> confirmStateChange);
   }
 
-  public final class SwipeableDefaults {
-    method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
-    method public float getVelocityThreshold();
-    method public androidx.compose.material.ResistanceConfig? resistanceConfig(java.util.Set<java.lang.Float> anchors, optional float factorAtMin, optional float factorAtMax);
-    property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> AnimationSpec;
-    property public final float VelocityThreshold;
-    field public static final androidx.compose.material.SwipeableDefaults INSTANCE;
-    field public static final float StandardResistanceFactor = 10.0f;
-    field public static final float StiffResistanceFactor = 20.0f;
+  @Deprecated public final class SwipeableDefaults {
+    method @Deprecated public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
+    method @Deprecated public float getVelocityThreshold();
+    method @Deprecated public androidx.compose.material.ResistanceConfig? resistanceConfig(java.util.Set<java.lang.Float> anchors, optional float factorAtMin, optional float factorAtMax);
+    property @Deprecated public final androidx.compose.animation.core.SpringSpec<java.lang.Float> AnimationSpec;
+    property @Deprecated public final float VelocityThreshold;
+    field @Deprecated public static final androidx.compose.material.SwipeableDefaults INSTANCE;
+    field @Deprecated public static final float StandardResistanceFactor = 10.0f;
+    field @Deprecated public static final float StiffResistanceFactor = 20.0f;
   }
 
   public final class SwipeableKt {
-    method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
-    ctor public SwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? animateTo(T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public final T getCurrentValue();
-    method public final float getDirection();
-    method public final androidx.compose.runtime.State<java.lang.Float> getOffset();
-    method public final androidx.compose.runtime.State<java.lang.Float> getOverflow();
-    method public final androidx.compose.material.SwipeProgress<T> getProgress();
-    method public final T getTargetValue();
-    method public final boolean isAnimationRunning();
-    method public final float performDrag(float delta);
-    method public final suspend Object? performFling(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? snapTo(T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final T currentValue;
-    property @androidx.compose.material.ExperimentalMaterialApi public final float direction;
-    property public final boolean isAnimationRunning;
-    property public final androidx.compose.runtime.State<java.lang.Float> offset;
-    property public final androidx.compose.runtime.State<java.lang.Float> overflow;
-    property @androidx.compose.material.ExperimentalMaterialApi public final androidx.compose.material.SwipeProgress<T> progress;
-    property @androidx.compose.material.ExperimentalMaterialApi public final T targetValue;
-    field public static final androidx.compose.material.SwipeableState.Companion Companion;
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
+    ctor @Deprecated public SwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? animateTo(T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @Deprecated public final T getCurrentValue();
+    method @Deprecated public final float getDirection();
+    method @Deprecated public final androidx.compose.runtime.State<java.lang.Float> getOffset();
+    method @Deprecated public final androidx.compose.runtime.State<java.lang.Float> getOverflow();
+    method @Deprecated public final androidx.compose.material.SwipeProgress<T> getProgress();
+    method @Deprecated public final T getTargetValue();
+    method @Deprecated public final boolean isAnimationRunning();
+    method @Deprecated public final float performDrag(float delta);
+    method @Deprecated public final suspend Object? performFling(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? snapTo(T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property @Deprecated public final T currentValue;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final float direction;
+    property @Deprecated public final boolean isAnimationRunning;
+    property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> offset;
+    property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> overflow;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final androidx.compose.material.SwipeProgress<T> progress;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final T targetValue;
+    field @Deprecated public static final androidx.compose.material.SwipeableState.Companion Companion;
   }
 
-  public static final class SwipeableState.Companion {
-    method public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.material.SwipeableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+  @Deprecated public static final class SwipeableState.Companion {
+    method @Deprecated public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.material.SwipeableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
   }
 
   @androidx.compose.runtime.Stable public interface SwitchColors {
@@ -912,8 +912,8 @@
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
   }
 
   @androidx.compose.runtime.Immutable public final class Typography {
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index f364bc2..c8319a15 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -457,10 +457,10 @@
     property public final int End;
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
-    ctor public FixedThreshold(float offset);
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
+    ctor @Deprecated public FixedThreshold(float offset);
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+    method @Deprecated public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
   }
 
   public final class FloatingActionButtonDefaults {
@@ -478,10 +478,10 @@
     method @androidx.compose.runtime.Composable public static void FloatingActionButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
-    ctor public FractionalThreshold(float fraction);
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.compose.material.FractionalThreshold copy(float fraction);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
+    ctor @Deprecated public FractionalThreshold(float fraction);
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+    method @Deprecated public androidx.compose.material.FractionalThreshold copy(float fraction);
   }
 
   public final class IconButtonKt {
@@ -625,15 +625,15 @@
     method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.RadioButtonColors colors);
   }
 
-  @androidx.compose.runtime.Immutable public final class ResistanceConfig {
-    ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
-    method public float computeResistance(float overflow);
-    method public float getBasis();
-    method public float getFactorAtMax();
-    method public float getFactorAtMin();
-    property public final float basis;
-    property public final float factorAtMax;
-    property public final float factorAtMin;
+  @Deprecated @androidx.compose.runtime.Immutable public final class ResistanceConfig {
+    ctor @Deprecated public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+    method @Deprecated public float computeResistance(float overflow);
+    method @Deprecated public float getBasis();
+    method @Deprecated public float getFactorAtMax();
+    method @Deprecated public float getFactorAtMin();
+    property @Deprecated public final float basis;
+    property @Deprecated public final float factorAtMax;
+    property @Deprecated public final float factorAtMin;
   }
 
   public final class ScaffoldKt {
@@ -745,14 +745,14 @@
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void Surface(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional androidx.compose.foundation.BorderStroke? border, optional float elevation, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class SwipeProgress<T> {
-    ctor public SwipeProgress(T from, T to, float fraction);
-    method public float getFraction();
-    method public T getFrom();
-    method public T getTo();
-    property public final float fraction;
-    property public final T from;
-    property public final T to;
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class SwipeProgress<T> {
+    ctor @Deprecated public SwipeProgress(T from, T to, float fraction);
+    method @Deprecated public float getFraction();
+    method @Deprecated public T getFrom();
+    method @Deprecated public T getTo();
+    property @Deprecated public final float fraction;
+    property @Deprecated public final T from;
+    property @Deprecated public final T to;
   }
 
   public final class SwipeToDismissKt {
@@ -760,47 +760,47 @@
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.DismissState rememberDismissState(optional androidx.compose.material.DismissValue initialValue, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissValue,java.lang.Boolean> confirmStateChange);
   }
 
-  public final class SwipeableDefaults {
-    method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
-    method public float getVelocityThreshold();
-    method public androidx.compose.material.ResistanceConfig? resistanceConfig(java.util.Set<java.lang.Float> anchors, optional float factorAtMin, optional float factorAtMax);
-    property public final androidx.compose.animation.core.SpringSpec<java.lang.Float> AnimationSpec;
-    property public final float VelocityThreshold;
-    field public static final androidx.compose.material.SwipeableDefaults INSTANCE;
-    field public static final float StandardResistanceFactor = 10.0f;
-    field public static final float StiffResistanceFactor = 20.0f;
+  @Deprecated public final class SwipeableDefaults {
+    method @Deprecated public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
+    method @Deprecated public float getVelocityThreshold();
+    method @Deprecated public androidx.compose.material.ResistanceConfig? resistanceConfig(java.util.Set<java.lang.Float> anchors, optional float factorAtMin, optional float factorAtMax);
+    property @Deprecated public final androidx.compose.animation.core.SpringSpec<java.lang.Float> AnimationSpec;
+    property @Deprecated public final float VelocityThreshold;
+    field @Deprecated public static final androidx.compose.material.SwipeableDefaults INSTANCE;
+    field @Deprecated public static final float StandardResistanceFactor = 10.0f;
+    field @Deprecated public static final float StiffResistanceFactor = 20.0f;
   }
 
   public final class SwipeableKt {
-    method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
-    ctor public SwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? animateTo(T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method public final T getCurrentValue();
-    method public final float getDirection();
-    method public final androidx.compose.runtime.State<java.lang.Float> getOffset();
-    method public final androidx.compose.runtime.State<java.lang.Float> getOverflow();
-    method public final androidx.compose.material.SwipeProgress<T> getProgress();
-    method public final T getTargetValue();
-    method public final boolean isAnimationRunning();
-    method public final float performDrag(float delta);
-    method public final suspend Object? performFling(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    method @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? snapTo(T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
-    property public final T currentValue;
-    property @androidx.compose.material.ExperimentalMaterialApi public final float direction;
-    property public final boolean isAnimationRunning;
-    property public final androidx.compose.runtime.State<java.lang.Float> offset;
-    property public final androidx.compose.runtime.State<java.lang.Float> overflow;
-    property @androidx.compose.material.ExperimentalMaterialApi public final androidx.compose.material.SwipeProgress<T> progress;
-    property @androidx.compose.material.ExperimentalMaterialApi public final T targetValue;
-    field public static final androidx.compose.material.SwipeableState.Companion Companion;
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
+    ctor @Deprecated public SwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? animateTo(T targetValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> anim, optional kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @Deprecated public final T getCurrentValue();
+    method @Deprecated public final float getDirection();
+    method @Deprecated public final androidx.compose.runtime.State<java.lang.Float> getOffset();
+    method @Deprecated public final androidx.compose.runtime.State<java.lang.Float> getOverflow();
+    method @Deprecated public final androidx.compose.material.SwipeProgress<T> getProgress();
+    method @Deprecated public final T getTargetValue();
+    method @Deprecated public final boolean isAnimationRunning();
+    method @Deprecated public final float performDrag(float delta);
+    method @Deprecated public final suspend Object? performFling(float velocity, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    method @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final suspend Object? snapTo(T targetValue, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+    property @Deprecated public final T currentValue;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final float direction;
+    property @Deprecated public final boolean isAnimationRunning;
+    property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> offset;
+    property @Deprecated public final androidx.compose.runtime.State<java.lang.Float> overflow;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final androidx.compose.material.SwipeProgress<T> progress;
+    property @Deprecated @androidx.compose.material.ExperimentalMaterialApi public final T targetValue;
+    field @Deprecated public static final androidx.compose.material.SwipeableState.Companion Companion;
   }
 
-  public static final class SwipeableState.Companion {
-    method public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.material.SwipeableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
+  @Deprecated public static final class SwipeableState.Companion {
+    method @Deprecated public <T> androidx.compose.runtime.saveable.Saver<androidx.compose.material.SwipeableState<T>,T> Saver(androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
   }
 
   @androidx.compose.runtime.Stable public interface SwitchColors {
@@ -912,8 +912,8 @@
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.text.TextStyle> LocalTextStyle;
   }
 
-  @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
-    method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+  @Deprecated @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
+    method @Deprecated public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
   }
 
   @androidx.compose.runtime.Immutable public final class Typography {
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
index afe146a..98704d1b 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@file:Suppress("Deprecation")
 
 package androidx.compose.material.samples
 
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
index 8cd376a..e4870c9 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
@@ -1440,9 +1440,10 @@
         }
 
         assertThat(drawerState.currentValue).isEqualTo(BottomDrawerValue.Closed)
-        assertThat(drawerState.anchoredDraggableState.hasAnchorForValue(BottomDrawerValue.Open))
+        assertThat(drawerState.anchoredDraggableState.anchors.hasAnchorFor(BottomDrawerValue.Open))
             .isFalse()
-        assertThat(drawerState.anchoredDraggableState.hasAnchorForValue(BottomDrawerValue.Expanded))
+        assertThat(drawerState.anchoredDraggableState.anchors
+            .hasAnchorFor(BottomDrawerValue.Expanded))
             .isFalse()
 
         scope.launch { drawerState.open() }
@@ -1476,9 +1477,10 @@
         }
 
         assertThat(drawerState.currentValue).isEqualTo(BottomDrawerValue.Closed)
-        assertThat(drawerState.anchoredDraggableState.hasAnchorForValue(BottomDrawerValue.Open))
+        assertThat(drawerState.anchoredDraggableState.anchors.hasAnchorFor(BottomDrawerValue.Open))
             .isFalse()
-        assertThat(drawerState.anchoredDraggableState.hasAnchorForValue(BottomDrawerValue.Expanded))
+        assertThat(drawerState.anchoredDraggableState.anchors
+            .hasAnchorFor(BottomDrawerValue.Expanded))
             .isFalse()
 
         scope.launch { drawerState.open() }
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetStateTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetStateTest.kt
index 15f9365..8a7c6e4 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetStateTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetStateTest.kt
@@ -99,7 +99,7 @@
 
     private fun ModalBottomSheetState(
         initialValue: ModalBottomSheetValue,
-        animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+        animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
         isSkipHalfExpanded: Boolean,
         confirmValueChange: (ModalBottomSheetValue) -> Boolean = { true },
         density: Density
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
index d5d6e55..e9e8271 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ModalBottomSheetTest.kt
@@ -850,6 +850,8 @@
         }
 
         showShortContent = true
+        // We use a immediate dispatcher in tests, so wait for composition
+        rule.waitForIdle()
         scope.launch { sheetState.show() } // We can't use LaunchedEffect with Swipeable in tests
         // yet, so we're invoking this outside of composition. See b/254115946.
 
@@ -1017,20 +1019,21 @@
         rule.waitForIdle()
         assertThat(state.currentValue).isEqualTo(ModalBottomSheetValue.HalfExpanded) // We should
         // retain the current value if possible
-        assertThat(state.anchoredDraggableState.anchors)
-            .containsKey(ModalBottomSheetValue.Hidden)
-        assertThat(state.anchoredDraggableState.anchors)
-            .containsKey(ModalBottomSheetValue.HalfExpanded)
-        assertThat(state.anchoredDraggableState.anchors).containsKey(ModalBottomSheetValue.Expanded)
+        assertThat(state.anchoredDraggableState.anchors.hasAnchorFor(ModalBottomSheetValue.Hidden))
+            .isTrue()
+        assertThat(
+            state.anchoredDraggableState.anchors.hasAnchorFor(ModalBottomSheetValue.HalfExpanded)
+        ).isTrue()
+        assertThat(
+            state.anchoredDraggableState.anchors.hasAnchorFor(ModalBottomSheetValue.Expanded)
+        ).isTrue()
 
         amountOfItems = 0 // When the sheet height is 0, we should only have a hidden anchor
         rule.waitForIdle()
         assertThat(state.currentValue).isEqualTo(ModalBottomSheetValue.Hidden)
-        assertThat(state.anchoredDraggableState.anchors).containsKey(ModalBottomSheetValue.Hidden)
-        assertThat(state.anchoredDraggableState.anchors)
-            .doesNotContainKey(ModalBottomSheetValue.HalfExpanded)
-        assertThat(state.anchoredDraggableState.anchors)
-            .doesNotContainKey(ModalBottomSheetValue.Expanded)
+        assertThat(state.anchoredDraggableState.anchors.hasAnchorFor(ModalBottomSheetValue.Hidden))
+            .isTrue()
+        assertThat(state.anchoredDraggableState.anchors.size).isEqualTo(1)
     }
 
     @Test
@@ -1236,12 +1239,9 @@
         }
 
         assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Hidden)
-        assertThat(sheetState.anchoredDraggableState.hasAnchorForValue(
-            ModalBottomSheetValue.HalfExpanded
-        )).isFalse()
-        assertThat(sheetState.anchoredDraggableState.hasAnchorForValue(
-            ModalBottomSheetValue.Expanded
-        )).isFalse()
+        val anchors = sheetState.anchoredDraggableState.anchors
+        assertThat(anchors.hasAnchorFor(ModalBottomSheetValue.HalfExpanded)).isFalse()
+        assertThat(anchors.hasAnchorFor(ModalBottomSheetValue.Expanded)).isFalse()
 
         scope.launch { sheetState.show() }
         rule.waitForIdle()
@@ -1273,11 +1273,11 @@
         }
 
         assertThat(sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Hidden)
-        assertThat(sheetState.anchoredDraggableState
-            .hasAnchorForValue(ModalBottomSheetValue.HalfExpanded))
+        assertThat(sheetState.anchoredDraggableState.anchors
+            .hasAnchorFor(ModalBottomSheetValue.HalfExpanded))
             .isFalse()
-        assertThat(sheetState.anchoredDraggableState
-            .hasAnchorForValue(ModalBottomSheetValue.Expanded))
+        assertThat(sheetState.anchoredDraggableState.anchors
+            .hasAnchorFor(ModalBottomSheetValue.Expanded))
             .isFalse()
 
         scope.launch { sheetState.show() }
@@ -1319,7 +1319,7 @@
         sheetState =
             ModalBottomSheetState(ModalBottomSheetValue.HalfExpanded, density = rule.density)
 
-        assertThat(sheetState.anchoredDraggableState.anchors).isEmpty()
+        assertThat(sheetState.anchoredDraggableState.anchors.size).isEqualTo(0)
         assertThat(sheetState.anchoredDraggableState.offset).isNaN()
 
         stateRestorationTester.emulateSavedInstanceStateRestore()
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
index 26b529d..a686c33 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATION") // Swipeable is deprecated
+
 package androidx.compose.material
 
 import androidx.compose.foundation.ScrollState
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableAnchorsTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableAnchorsTest.kt
deleted file mode 100644
index e398ae4..0000000
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableAnchorsTest.kt
+++ /dev/null
@@ -1,245 +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.compose.material.anchoredDraggable
-
-import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.foundation.layout.size
-import androidx.compose.material.AnchoredDraggableDefaults.ReconcileAnimationOnAnchorChangedCallback
-import androidx.compose.material.AnchoredDraggableState
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.A
-import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.B
-import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.C
-import androidx.compose.material.animateTo
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@LargeTest
-@OptIn(ExperimentalMaterialApi::class)
-class AnchoredDraggableAnchorsTest {
-
-    @get:Rule
-    val rule = createComposeRule()
-
-    @Test
-    fun anchoredDraggable_reconcileAnchorChangeHandler_retargetsAnimationWhenOffsetChanged() {
-        val animationDurationMillis = 2000
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
-        lateinit var scope: CoroutineScope
-
-        val firstAnchors = mapOf(A to 0f, B to 100f, C to 200f)
-        val secondAnchors = mapOf(A to 300f, B to 400f, C to 600f)
-        var anchors = firstAnchors
-        var size by mutableStateOf(100)
-
-        val animationTarget = B
-
-        rule.setContent {
-            state = remember {
-                AnchoredDraggableState(
-                    initialValue = A,
-                    animationSpec = tween(animationDurationMillis, easing = LinearEasing),
-                    positionalThreshold = defaultPositionalThreshold(),
-                    velocityThreshold = defaultVelocityThreshold()
-                )
-            }
-            scope = rememberCoroutineScope()
-            val anchorChangeHandler = remember(state, scope) {
-                ReconcileAnimationOnAnchorChangedCallback(
-                    state,
-                    scope
-                )
-            }
-            Box(
-                Modifier
-                    .size(size.dp) // Trigger anchor recalculation when size changes
-                    .onSizeChanged { state.updateAnchors(anchors, anchorChangeHandler) }
-            )
-        }
-
-        assertThat(state.currentValue == A)
-        rule.mainClock.autoAdvance = false
-
-        scope.launch { state.animateTo(animationTarget) }
-
-        rule.mainClock.advanceTimeByFrame()
-        anchors = secondAnchors
-        size = 200
-        rule.mainClock.autoAdvance = true
-        rule.waitForIdle()
-
-        assertThat(state.offset).isEqualTo(secondAnchors.getValue(animationTarget))
-    }
-
-    @Test
-    fun anchoredDraggable_reconcileAnchorChangeHandler_snapsWhenPreviousAnchorRemoved() {
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold(),
-            velocityThreshold = defaultVelocityThreshold()
-        )
-
-        val firstAnchors = mapOf(A to 0f, B to 100f, C to 200f)
-        val secondAnchors = mapOf(B to 400f, C to 600f)
-        var anchors = firstAnchors
-        var size by mutableStateOf(100)
-
-        rule.setContent {
-            val scope = rememberCoroutineScope()
-            val anchorChangeHandler = remember(state, scope) {
-                ReconcileAnimationOnAnchorChangedCallback(state, scope)
-            }
-            Box(
-                Modifier
-                    .size(size.dp) // Trigger anchor recalculation when size changes
-                    .onSizeChanged { state.updateAnchors(anchors, anchorChangeHandler) }
-            )
-        }
-
-        assertThat(state.currentValue == A)
-
-        anchors = secondAnchors
-        size = 200
-        rule.waitForIdle()
-
-        assertThat(state.currentValue).isEqualTo(B)
-    }
-
-    @Test
-    fun anchoredDraggable_anchorChangeHandler_calledWithUpdatedAnchorsWhenChanged() {
-        var anchorChangeHandlerInvocationCount = 0
-        var actualPreviousAnchors: Map<AnchoredDraggableTestValue, Float>? = null
-        var actualNewAnchors: Map<AnchoredDraggableTestValue, Float>? = null
-        val testChangeHandler = AnchorChangedCallback { _, previousAnchors, newAnchors ->
-            anchorChangeHandlerInvocationCount++
-            actualPreviousAnchors = previousAnchors
-            actualNewAnchors = newAnchors
-        }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold(),
-            velocityThreshold = defaultVelocityThreshold()
-        )
-        val initialSize = 100.dp
-        var size: Dp by mutableStateOf(initialSize)
-        rule.setContent {
-            Box(
-                Modifier
-                    .requiredSize(size) // Trigger anchor recalculation when size changes
-                    .onSizeChanged { layoutSize ->
-                        state.updateAnchors(
-                            mapOf(
-                                A to 0f,
-                                B to layoutSize.height / 2f,
-                                C to layoutSize.height.toFloat()
-                            ),
-                            testChangeHandler
-                        )
-                    }
-            )
-        }
-
-        // The change handler should not get invoked when the anchors are first set
-        assertThat(anchorChangeHandlerInvocationCount).isEqualTo(0)
-
-        val expectedPreviousAnchors = state.anchors
-        size = 200.dp // Recompose with new size so anchors change
-        val sizePx = with(rule.density) { size.roundToPx() }
-        val layoutSize = IntSize(sizePx, sizePx)
-        val expectedNewAnchors = mapOf(
-            A to 0f,
-            B to layoutSize.height / 2f,
-            C to layoutSize.height.toFloat()
-        )
-        rule.waitForIdle()
-
-        assertThat(anchorChangeHandlerInvocationCount).isEqualTo(1)
-        assertThat(actualPreviousAnchors).isEqualTo(expectedPreviousAnchors)
-        assertThat(actualNewAnchors).isEqualTo(expectedNewAnchors)
-    }
-
-    @Test
-    fun anchoredDraggable_anchorChangeHandler_invokedWithPreviousTarget() {
-        var recordedPreviousTargetValue: AnchoredDraggableTestValue? = null
-        val testChangeHandler =
-            AnchorChangedCallback<AnchoredDraggableTestValue> { previousTarget, _, _ ->
-                recordedPreviousTargetValue = previousTarget
-            }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = { totalDistance -> totalDistance * 0.5f },
-            velocityThreshold = defaultVelocityThreshold()
-        )
-        var anchors = mapOf(
-            A to 0f,
-            B to 100f,
-            C to 200f
-        )
-        state.updateAnchors(anchors, testChangeHandler)
-
-        assertThat(state.targetValue).isEqualTo(A)
-        anchors = mapOf(B to 500f)
-        state.updateAnchors(anchors, testChangeHandler)
-        assertThat(recordedPreviousTargetValue).isEqualTo(A) // A is not in the anchors anymore, so
-        // we can be sure that is not the targetValue calculated from the new anchors
-    }
-
-    @Test
-    fun anchoredDraggable_anchorChangeHandler_invokedIfInitialValueNotInInitialAnchors() {
-        var anchorChangeHandlerInvocationCount = 0
-        val testChangeHandler = AnchorChangedCallback<AnchoredDraggableTestValue> { _, _, _ ->
-            anchorChangeHandlerInvocationCount++
-        }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold(),
-            velocityThreshold = defaultVelocityThreshold()
-        )
-        state.updateAnchors(mapOf(B to 100f, C to 200f), testChangeHandler)
-
-        assertThat(anchorChangeHandlerInvocationCount).isEqualTo(1)
-    }
-
-    private fun defaultPositionalThreshold(): (totalDistance: Float) -> Float = with(rule.density) {
-        { 56.dp.toPx() }
-    }
-    private fun defaultVelocityThreshold(): () -> Float = with(rule.density) {
-        { 125.dp.toPx() }
-    }
-}
\ No newline at end of file
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableGestureTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableGestureTest.kt
index aa3c2e2..ae56214 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableGestureTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableGestureTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.compose.material.anchoredDraggable
 
+import androidx.compose.animation.core.tween
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Box
@@ -24,6 +25,7 @@
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.material.AnchoredDraggableState
 import androidx.compose.material.AutoTestFrameClock
+import androidx.compose.material.DraggableAnchors
 import androidx.compose.material.ExperimentalMaterialApi
 import androidx.compose.material.anchoredDraggable
 import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.A
@@ -78,13 +80,14 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
-        val anchors = mapOf(
-            A to 0f,
-            B to 250f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
         state.updateAnchors(anchors)
 
         rule.setContent {
@@ -120,27 +123,27 @@
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(B)
-        assertThat(state.offset).isEqualTo(anchors.getValue(B))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeRight(startX = right / 2, endX = right) }
         rule.waitForIdle()
         assertThat(state.currentValue).isEqualTo(C)
-        assertThat(state.offset).isEqualTo(anchors.getValue(C))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(C))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeLeft(endX = right / 2) }
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(B)
-        assertThat(state.offset).isEqualTo(anchors.getValue(B))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeLeft(startX = right / 2) }
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(A)
-        assertThat(state.offset).isEqualTo(anchors.getValue(A))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(A))
     }
 
     @Test
@@ -148,13 +151,14 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
-        val anchors = mapOf(
-            A to 0f,
-            B to 250f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
         state.updateAnchors(anchors)
 
         rule.setContent {
@@ -190,27 +194,27 @@
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(B)
-        assertThat(state.offset).isEqualTo(anchors.getValue(B))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeDown(startY = bottom / 2, endY = bottom) }
         rule.waitForIdle()
         assertThat(state.currentValue).isEqualTo(C)
-        assertThat(state.offset).isEqualTo(anchors.getValue(C))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(C))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeUp(startY = bottom, endY = bottom / 2) }
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(B)
-        assertThat(state.offset).isEqualTo(anchors.getValue(B))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(B))
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput { swipeUp(startY = bottom / 2, endY = top) }
         rule.waitForIdle()
 
         assertThat(state.currentValue).isEqualTo(A)
-        assertThat(state.offset).isEqualTo(anchors.getValue(A))
+        assertThat(state.offset).isEqualTo(anchors.positionOf(A))
     }
 
     @Test
@@ -218,13 +222,14 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
-        val anchors = mapOf(
-            A to 0f,
-            B to 250f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
         state.updateAnchors(anchors)
 
         rule.setContent {
@@ -269,13 +274,14 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
-        val anchors = mapOf(
-            A to 0f,
-            B to 250f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
         state.updateAnchors(anchors)
 
         rule.setContent {
@@ -322,7 +328,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = { totalDistance -> totalDistance * positionalThreshold },
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -335,11 +342,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -354,8 +361,8 @@
             }
         }
 
-        val positionOfA = state.anchors.getValue(A)
-        val positionOfB = state.anchors.getValue(B)
+        val positionOfA = state.anchors.positionOf(A)
+        val positionOfB = state.anchors.positionOf(B)
         val distance = abs(positionOfA - positionOfB)
         state.dispatchRawDelta(positionOfA + distance * (absThreshold * 0.9f))
         rule.waitForIdle()
@@ -401,7 +408,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = { totalDistance -> totalDistance * positionalThreshold },
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -414,11 +422,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -433,8 +441,8 @@
             }
         }
 
-        val positionOfA = state.anchors.getValue(A)
-        val positionOfB = state.anchors.getValue(B)
+        val positionOfA = state.anchors.positionOf(A)
+        val positionOfB = state.anchors.positionOf(B)
         val distance = abs(positionOfA - positionOfB)
         state.dispatchRawDelta(positionOfA + distance * (absThreshold * 0.9f))
         rule.waitForIdle()
@@ -481,7 +489,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = { positionalThresholdPx },
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -494,11 +503,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -564,7 +573,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = { positionalThresholdPx },
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -577,11 +587,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -647,14 +657,15 @@
             val state = AnchoredDraggableState(
                 initialValue = A,
                 positionalThreshold = DefaultPositionalThreshold,
-                velocityThreshold = { velocityPx / 2f }
+                velocityThreshold = { velocityPx / 2f },
+                animationSpec = tween()
             )
             state.updateAnchors(
-                mapOf(
-                    A to 0f,
-                    B to 100f,
-                    C to 200f
-                )
+                DraggableAnchors {
+                    A at 0f
+                    B at 100f
+                    C at 200f
+                }
             )
             state.dispatchRawDelta(60f)
             state.settle(velocityPx)
@@ -670,14 +681,15 @@
             val state = AnchoredDraggableState(
                 initialValue = A,
                 velocityThreshold = { velocityPx },
-                positionalThreshold = { Float.POSITIVE_INFINITY }
+                positionalThreshold = { Float.POSITIVE_INFINITY },
+                animationSpec = tween()
             )
             state.updateAnchors(
-                mapOf(
-                    A to 0f,
-                    B to 100f,
-                    C to 200f
-                )
+                DraggableAnchors {
+                    A at 0f
+                    B at 100f
+                    C at 200f
+                }
             )
             state.dispatchRawDelta(60f)
             state.settle(velocityPx / 2)
@@ -690,7 +702,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = { with(rule.density) { velocityThreshold.toPx() } }
+            velocityThreshold = { with(rule.density) { velocityThreshold.toPx() } },
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -703,11 +716,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -741,7 +754,8 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             velocityThreshold = { with(rule.density) { velocityThreshold.toPx() } },
-            positionalThreshold = { Float.POSITIVE_INFINITY }
+            positionalThreshold = { Float.POSITIVE_INFINITY },
+            animationSpec = tween()
         )
         rule.setContent {
             Box(Modifier.fillMaxSize()) {
@@ -754,11 +768,11 @@
                             orientation = Orientation.Horizontal
                         )
                         .onSizeChanged { layoutSize ->
-                            val anchors = mapOf(
-                                A to 0f,
-                                B to layoutSize.width / 2f,
-                                C to layoutSize.width.toFloat()
-                            )
+                            val anchors = DraggableAnchors {
+                                A at 0f
+                                B at layoutSize.width / 2f
+                                C at layoutSize.width.toFloat()
+                            }
                             state.updateAnchors(anchors)
                         }
                         .offset {
@@ -788,14 +802,15 @@
 
     @Test
     fun anchoredDraggable_dragBeyondBounds_clampsAndSwipesBack() {
-        val anchors = mapOf(
-            A to 0f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            C at 500f
+        }
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = DefaultPositionalThreshold,
-            velocityThreshold = { 0f }
+            velocityThreshold = { 0f },
+            animationSpec = tween()
         )
         state.updateAnchors(anchors)
         rule.setContent {
@@ -821,7 +836,7 @@
         }
 
         val overdrag = 100f
-        val maxBound = state.anchors.getValue(C)
+        val maxBound = state.anchors.positionOf(C)
 
         rule.onNodeWithTag(AnchoredDraggableTestTag)
             .performTouchInput {
@@ -842,15 +857,16 @@
     @Test
     fun anchoredDraggable_animationCancelledByDrag_resetsTargetValueToClosest() {
         rule.mainClock.autoAdvance = false
-        val anchors = mapOf(
-            A to 0f,
-            B to 250f,
-            C to 500f
-        )
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 250f
+            C at 500f
+        }
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = { totalDistance -> totalDistance * 0.5f },
-            velocityThreshold = DefaultVelocityThreshold
+            velocityThreshold = DefaultVelocityThreshold,
+            animationSpec = tween()
         )
         state.updateAnchors(anchors)
         lateinit var scope: CoroutineScope
@@ -885,7 +901,7 @@
         scope.launch { state.animateTo(C) }
 
         rule.mainClock.advanceTimeUntil {
-            state.requireOffset() > abs(state.requireOffset() - anchors.getValue(B))
+            state.requireOffset() > abs(state.requireOffset() - anchors.positionOf(B))
         } // Advance until our closest anchor is B
         assertThat(state.targetValue).isEqualTo(C)
 
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
index 1a7dfc5..66d17fb 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/anchoredDraggable/AnchoredDraggableStateTest.kt
@@ -26,25 +26,21 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.requiredSize
-import androidx.compose.material.AnchoredDraggableDefaults
 import androidx.compose.material.AnchoredDraggableState
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
+import androidx.compose.material.DraggableAnchors
 import androidx.compose.material.ExperimentalMaterialApi
 import androidx.compose.material.anchoredDraggable
 import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.A
 import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.B
 import androidx.compose.material.anchoredDraggable.AnchoredDraggableTestValue.C
 import androidx.compose.material.animateTo
-import androidx.compose.material.rememberAnchoredDraggableState
 import androidx.compose.material.snapTo
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.runtime.withFrameNanos
 import androidx.compose.testutils.WithTouchSlop
 import androidx.compose.ui.Modifier
@@ -65,13 +61,18 @@
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.TimeUnit
 import kotlin.math.roundToInt
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.test.runTest
 import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
@@ -90,9 +91,13 @@
 
     @Test
     fun anchoredDraggable_state_canSkipStateByFling() {
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
         rule.setContent {
-            state = rememberAnchoredDraggableState(initialValue = A)
             Box(Modifier.fillMaxSize()) {
                 Box(
                     Modifier
@@ -104,11 +109,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -133,9 +138,13 @@
 
     @Test
     fun anchoredDraggable_targetState_updatedOnSwipe() {
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
         rule.setContent {
-            state = rememberAnchoredDraggableState(initialValue = A)
             Box(Modifier.fillMaxSize()) {
                 Box(
                     Modifier
@@ -147,11 +156,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -199,18 +208,14 @@
         rule.mainClock.autoAdvance = false
         val animationDuration = 300
         val frameLengthMillis = 16L
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            animationSpec = tween(animationDuration, easing = LinearEasing),
+            positionalThreshold = { distance -> distance * 0.5f },
+            velocityThreshold = defaultVelocityThreshold
+        )
         lateinit var scope: CoroutineScope
         rule.setContent {
-            val velocityThreshold = AnchoredDraggableDefaults.velocityThreshold
-            state = remember(velocityThreshold) {
-                AnchoredDraggableState(
-                    initialValue = A,
-                    animationSpec = tween(animationDuration, easing = LinearEasing),
-                    positionalThreshold = { distance -> distance * 0.5f },
-                    velocityThreshold = velocityThreshold
-                )
-            }
             scope = rememberCoroutineScope()
             Box(Modifier.fillMaxSize()) {
                 Box(
@@ -223,11 +228,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -266,44 +271,14 @@
     }
 
     @Test
-    fun anchoredDraggable_closestValue() {
-        val initialValue = A
-        val initialValueOffset = 0f
-        val state = AnchoredDraggableState(
-            initialValue = initialValue,
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
-        )
-        val anchors = mapOf(
-            initialValue to initialValueOffset,
-            B to 200f,
-            C to 400f
-        )
-        state.updateAnchors(anchors)
-
-        assertThat(state.offset).isEqualTo(initialValueOffset)
-        assertThat(state.currentValue).isEqualTo(A)
-        assertThat(state.closestValue).isEqualTo(A)
-
-        val aToBDistance = 200f
-        val firstTargetOffset = aToBDistance * 0.4f
-        state.dispatchRawDelta(firstTargetOffset)
-        assertThat(state.offset).isEqualTo(firstTargetOffset)
-        assertThat(state.currentValue).isEqualTo(A)
-        assertThat(state.closestValue).isEqualTo(B)
-
-        val secondTargetOffset = aToBDistance * 0.6f
-        state.dispatchRawDelta(secondTargetOffset - state.offset)
-        assertThat(state.offset).isEqualTo(secondTargetOffset)
-        assertThat(state.currentValue).isEqualTo(A)
-        assertThat(state.closestValue).isEqualTo(B)
-    }
-
-    @Test
     fun anchoredDraggable_progress_matchesSwipePosition() {
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
         rule.setContent {
-            state = rememberAnchoredDraggableState(initialValue = A)
             WithTouchSlop(touchSlop = 0f) {
                 Box(Modifier.fillMaxSize()) {
                     Box(
@@ -316,11 +291,11 @@
                             )
                             .onSizeChanged { layoutSize ->
                                 state.updateAnchors(
-                                    mapOf(
-                                        A to 0f,
-                                        B to layoutSize.width / 2f,
-                                        C to layoutSize.width.toFloat()
-                                    )
+                                    DraggableAnchors {
+                                        A at 0f
+                                        B at layoutSize.width / 2f
+                                        C at layoutSize.width.toFloat()
+                                    }
                                 )
                             }
                             .offset {
@@ -336,8 +311,8 @@
             }
         }
 
-        val anchorA = state.anchors.getValue(A)
-        val anchorB = state.anchors.getValue(B)
+        val anchorA = state.anchors.positionOf(A)
+        val anchorB = state.anchors.positionOf(B)
         val almostAnchorB = anchorB * 0.9f
         var expectedProgress = almostAnchorB / (anchorB - anchorA)
 
@@ -359,9 +334,13 @@
 
     @Test
     fun anchoredDraggable_snapTo_updatesImmediately() = runBlocking {
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
         rule.setContent {
-            state = rememberAnchoredDraggableState(initialValue = A)
             Box(Modifier.fillMaxSize()) {
                 Box(
                     Modifier
@@ -373,11 +352,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -403,13 +382,23 @@
 
         val initialState = C
         val animationSpec = tween<Float>(durationMillis = 1000)
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = initialState,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = animationSpec
+        )
         lateinit var scope: CoroutineScope
 
         restorationTester.setContent {
-            state = rememberAnchoredDraggableState(initialState, animationSpec)
             SideEffect {
-                state.updateAnchors(mapOf(A to 0f, B to 100f, C to 200f))
+                state.updateAnchors(
+                    DraggableAnchors {
+                        A at 0f
+                        B at 100f
+                        C at 200f
+                    }
+                )
             }
             scope = rememberCoroutineScope()
         }
@@ -433,7 +422,14 @@
     fun anchoredDraggable_targetState_accessedInInitialComposition() {
         lateinit var targetState: AnchoredDraggableTestValue
         rule.setContent {
-            val state = rememberAnchoredDraggableState(initialValue = B)
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
             LaunchedEffect(state.targetValue) {
                 targetState = state.targetValue
             }
@@ -448,11 +444,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -474,7 +470,14 @@
     fun anchoredDraggable_progress_accessedInInitialComposition() {
         var progress = Float.NaN
         rule.setContent {
-            val state = rememberAnchoredDraggableState(initialValue = B)
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
             LaunchedEffect(state.progress) {
                 progress = state.progress
             }
@@ -489,11 +492,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -515,10 +518,14 @@
     @Ignore("Todo: Fix differences between tests and real code - this shouldn't work :)")
     fun anchoredDraggable_requireOffset_accessedInInitialComposition_throws() {
         var exception: Throwable? = null
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = B,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
         var offset: Float? = null
         rule.setContent {
-            state = rememberAnchoredDraggableState(initialValue = B)
             Box(Modifier.fillMaxSize()) {
                 Box(
                     Modifier
@@ -530,11 +537,11 @@
                         )
                         .onSizeChanged { layoutSize ->
                             state.updateAnchors(
-                                mapOf(
-                                    A to 0f,
-                                    B to layoutSize.width / 2f,
-                                    C to layoutSize.width.toFloat()
-                                )
+                                DraggableAnchors {
+                                    A at 0f
+                                    B at layoutSize.width / 2f
+                                    C at layoutSize.width.toFloat()
+                                }
                             )
                         }
                         .offset {
@@ -550,7 +557,7 @@
             exception = runCatching { offset = state.requireOffset() }.exceptionOrNull()
         }
 
-        assertThat(state.anchors).isNotEmpty()
+        assertThat(state.anchors.size).isNotEqualTo(0)
         assertThat(offset).isNull()
         assertThat(exception).isNotNull()
         assertThat(exception).isInstanceOf(IllegalStateException::class.java)
@@ -562,7 +569,14 @@
     fun anchoredDraggable_requireOffset_accessedInEffect_doesntThrow() {
         var exception: Throwable? = null
         rule.setContent {
-            val state = rememberAnchoredDraggableState(initialValue = B)
+            val state = remember {
+                AnchoredDraggableState(
+                    initialValue = B,
+                    positionalThreshold = defaultPositionalThreshold,
+                    velocityThreshold = defaultVelocityThreshold,
+                    animationSpec = defaultAnimationSpec
+                )
+            }
             LaunchedEffect(Unit) {
                 exception = runCatching { state.requireOffset() }.exceptionOrNull()
             }
@@ -576,10 +590,10 @@
         rule.mainClock.autoAdvance = false
         val minBound = 0f
         val maxBound = 500f
-        val anchors = mapOf(
-            A to minBound,
-            C to maxBound
-        )
+        val anchors = DraggableAnchors {
+            A at minBound
+            C at maxBound
+        }
 
         val animationSpec = FloatSpringSpec(dampingRatio = Spring.DampingRatioHighBouncy)
         val animationDuration = animationSpec.getDurationNanos(
@@ -588,15 +602,16 @@
             initialVelocity = 0f
         ).let { TimeUnit.NANOSECONDS.toMillis(it) }
 
-        lateinit var state: AnchoredDraggableState<AnchoredDraggableTestValue>
+        val state = AnchoredDraggableState(
+            initialValue = A,
+            positionalThreshold = defaultPositionalThreshold,
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = animationSpec
+        )
         lateinit var scope: CoroutineScope
 
         rule.setContent {
             scope = rememberCoroutineScope()
-            state = rememberAnchoredDraggableState(
-                initialValue = A,
-                animationSpec = animationSpec
-            )
             SideEffect {
                 state.updateAnchors(anchors)
             }
@@ -629,43 +644,7 @@
             highestOffset = state.requireOffset()
             rule.mainClock.advanceTimeBy(16)
         }
-        assertThat(highestOffset).isGreaterThan(anchors.getValue(C))
-    }
-
-    @Test
-    fun anchoredDraggable_bounds_minBoundIsSmallestAnchor() {
-        var minBound = 0f
-        var maxBound = 500f
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
-        )
-        state.updateAnchors(
-            mapOf(
-                A to minBound,
-                B to maxBound / 2,
-                C to maxBound
-            )
-        )
-        var size by mutableStateOf(100.dp)
-
-        assertThat(state.minOffset).isEqualTo(minBound)
-        assertThat(state.maxOffset).isEqualTo(maxBound)
-
-        minBound *= 3
-        maxBound *= 10
-        state.updateAnchors(
-            mapOf(
-                A to minBound,
-                C to maxBound
-            )
-        )
-        size = 200.dp
-        rule.waitForIdle()
-
-        assertThat(state.minOffset).isEqualTo(minBound)
-        assertThat(state.maxOffset).isEqualTo(maxBound)
+        assertThat(highestOffset).isGreaterThan(anchors.positionOf(C))
     }
 
     @Test
@@ -673,9 +652,10 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        assertThat(state.anchors).isEmpty()
+        assertThat(state.anchors.size).isEqualTo(0)
         assertThat(state.currentValue).isEqualTo(A)
         runBlocking { state.animateTo(B) }
         assertThat(state.currentValue).isEqualTo(B)
@@ -686,78 +666,202 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        assertThat(state.anchors).isEmpty()
+        assertThat(state.anchors.size).isEqualTo(0)
         assertThat(state.currentValue).isEqualTo(A)
         runBlocking { state.snapTo(B) }
         assertThat(state.currentValue).isEqualTo(B)
     }
 
     @Test
-    fun anchoredDraggable_updateAnchors_initialUpdate_initialValueInAnchors_shouldntUpdate() {
-        var anchorChangeHandlerInvoked = false
-        val testAnchorChangeHandler =
-            AnchorChangedCallback<AnchoredDraggableTestValue> { _, _, _ ->
-                anchorChangeHandlerInvoked = true
-            }
-        val state = AnchoredDraggableState(
+    fun anchoredDraggable_updateAnchors_noOngoingDrag_shouldUpdateOffset() {
+        val anchoredDraggableState = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(A to 200f, C to 300f)
-        state.updateAnchors(anchors, testAnchorChangeHandler)
-        assertThat(anchorChangeHandlerInvoked).isFalse()
+
+        assertThat(anchoredDraggableState.currentValue).isEqualTo(A)
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(A)
+        assertThat(anchoredDraggableState.offset).isNaN()
+
+        val offsetAtB = 100f
+        anchoredDraggableState.updateAnchors(
+            newAnchors = DraggableAnchors {
+                A at 0f
+                B at offsetAtB
+            },
+            newTarget = B
+        )
+        assertThat(anchoredDraggableState.currentValue).isEqualTo(B)
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(B)
+        assertThat(anchoredDraggableState.offset).isEqualTo(offsetAtB)
     }
 
+    @OptIn(ExperimentalCoroutinesApi::class)
     @Test
-    fun anchoredDraggable_updateAnchors_initialUpdate_initialValueNotInAnchors_shouldUpdate() {
-        var anchorChangeHandlerInvoked = false
-        val testAnchorChangedCallback =
-            AnchorChangedCallback<AnchoredDraggableTestValue> { _, _, _ ->
-                anchorChangeHandlerInvoked = true
-            }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+    fun anchoredDraggable_updateAnchors_ongoingDrag_shouldRestartDrag() = runTest {
+        // Given an anchored draggable state
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = 1,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(B to 200f, C to 300f)
-        state.updateAnchors(anchors, testAnchorChangedCallback)
-        assertThat(anchorChangeHandlerInvoked).isTrue()
+
+        val anchorUpdates = Channel<DraggableAnchors<Int>>()
+        val dragJob = launch {
+            anchoredDraggableState.anchoredDrag { newAnchors ->
+                anchorUpdates.send(newAnchors)
+                suspendIndefinitely()
+            }
+        }
+
+        val firstAnchors = anchorUpdates.receive()
+        assertThat(firstAnchors.size).isEqualTo(0)
+
+        // When the anchors change
+        val newAnchors = DraggableAnchors {
+            1 at 100f
+            2 at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors)
+        }
+
+        // Then the block should be invoked with the new anchors
+        assertThat(dragJob.isActive).isTrue()
+        val secondAnchors = anchorUpdates.receive()
+        assertThat(secondAnchors).isEqualTo(newAnchors)
+        dragJob.cancel()
     }
 
+    @OptIn(ExperimentalCoroutinesApi::class)
     @Test
-    fun anchoredDraggable_updateAnchors_updateExistingAnchors_shouldUpdate() {
-        var anchorChangeHandlerInvoked = false
-        val testAnchorChangedCallback =
-            AnchorChangedCallback<AnchoredDraggableTestValue> { _, _, _ ->
-                anchorChangeHandlerInvoked = true
-            }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+    fun anchoredDraggable_updateAnchors_anchoredDrag_invokedWithLatestAnchors() = runTest {
+        // Given an anchored draggable state
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = 1,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
 
-        state.updateAnchors(anchors, testAnchorChangedCallback)
-        assertThat(anchorChangeHandlerInvoked).isFalse()
+        val anchorUpdates = Channel<DraggableAnchors<Int>>()
+        val dragJob = launch(Dispatchers.Unconfined) {
+            anchoredDraggableState.anchoredDrag { newAnchors ->
+                anchorUpdates.send(newAnchors)
+                suspendIndefinitely()
+            }
+        }
 
-        state.updateAnchors(mapOf(A to 100f, B to 500f, C to 700f), testAnchorChangedCallback)
-        assertThat(anchorChangeHandlerInvoked).isTrue()
+        val firstAnchors = anchorUpdates.receive()
+        assertThat(firstAnchors.size).isEqualTo(0)
+
+        // When the anchors change
+        val newAnchors = DraggableAnchors {
+            1 at 100f
+            2 at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors)
+        }
+
+        // Then the block should be invoked with the new anchors
+        assertThat(dragJob.isActive).isTrue()
+        val secondAnchors = anchorUpdates.receive()
+        assertThat(secondAnchors).isEqualTo(newAnchors)
+        dragJob.cancel()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_updateAnchors_anchoredDrag_invokedWithLatestTarget() = runTest {
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = A,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        anchoredDraggableState.updateAnchors(
+            DraggableAnchors {
+                A at 0f
+                B at 200f
+            }
+        )
+
+        assertThat(anchoredDraggableState.targetValue).isEqualTo(A)
+
+        val firstExpectedTarget = B
+        val targetUpdates = Channel<AnchoredDraggableTestValue>()
+        val dragJob = launch(Dispatchers.Unconfined) {
+            anchoredDraggableState.anchoredDrag(firstExpectedTarget) { _, latestTarget ->
+                targetUpdates.send(latestTarget)
+                suspendIndefinitely()
+            }
+        }
+
+        val firstTarget = targetUpdates.receive()
+        assertThat(firstTarget).isEqualTo(firstExpectedTarget)
+
+        // When the anchors and target change
+        val newTarget = A
+        val newAnchors = DraggableAnchors {
+            A at 100f
+            B at 200f
+        }
+        Snapshot.withMutableSnapshot {
+            anchoredDraggableState.updateAnchors(newAnchors, newTarget)
+        }
+
+        // Then the block should be invoked with the new anchors
+        val secondTarget = targetUpdates.receive()
+        assertThat(secondTarget).isEqualTo(newTarget)
+        dragJob.cancel()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun anchoredDraggable_dragCompletesExceptionally_cleansUp() = runTest {
+        val anchoredDraggableState = AnchoredDraggableState(
+            initialValue = A,
+            defaultPositionalThreshold,
+            defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
+        )
+        val cancellationSignal = CompletableDeferred(false)
+        val anchoredDragUpdates = Channel<Unit>()
+        val dragJob = launch {
+            anchoredDraggableState.anchoredDrag {
+                anchoredDragUpdates.send(Unit)
+                cancellationSignal.await()
+                cancel()
+            }
+        }
+
+        assertThat(dragJob.isActive).isTrue()
+        assertThat(anchoredDragUpdates.receive()).isEqualTo(Unit)
+        cancellationSignal.complete(true)
+        dragJob.join()
+        assertThat(dragJob.isCancelled).isTrue()
     }
 
     @Test
     fun anchoredDraggable_customDrag_updatesOffset() = runBlocking {
-
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
 
         state.updateAnchors(anchors)
         state.anchoredDrag {
@@ -774,13 +878,17 @@
 
     @Test
     fun anchoredDraggable_customDrag_updatesVelocity() = runBlocking {
-
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
 
         state.updateAnchors(anchors)
         state.anchoredDrag {
@@ -797,13 +905,18 @@
         val state = AnchoredDraggableState(
             initialValue = A,
             positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
+            velocityThreshold = defaultVelocityThreshold,
+            animationSpec = defaultAnimationSpec
         )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 200f
+            C at 300f
+        }
 
         state.updateAnchors(anchors)
         dragScope.launch(start = CoroutineStart.UNDISPATCHED) {
-            state.anchoredDrag(targetValue = C) {
+            state.anchoredDrag(targetValue = C) { _, _ ->
                 while (isActive) {
                     withFrameNanos {
                         dragTo(200f)
@@ -817,107 +930,38 @@
     }
 
     @Test
-    fun anchoredDraggable_customDrag_anchorsPropagation() = runBlocking {
-        val clock = HandPumpTestFrameClock()
-        val dragScope = CoroutineScope(clock)
-
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
-        )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
-        var providedAnchors = emptyMap<AnchoredDraggableTestValue, Float>()
-
-        state.updateAnchors(anchors)
-        dragScope.launch(start = CoroutineStart.UNDISPATCHED) {
-            state.anchoredDrag(targetValue = C) { anchors ->
-                providedAnchors = anchors
-            }
+    fun anchoredDraggable_constructorWithAnchors_updatesAnchorsAndInitializes() {
+        val initialValueOffset = 0f
+        val anchors = DraggableAnchors {
+            A at initialValueOffset
+            B at 200f
         }
-        clock.advanceByFrame()
-        assertThat(providedAnchors).isEqualTo(anchors)
-    }
-
-    @Test
-    fun anchoredDraggable_customDrag_doesntCallConfirm() = runBlocking {
-
-        var counter: Int = 0
-
         val state = AnchoredDraggableState(
             initialValue = A,
+            anchors = anchors,
             positionalThreshold = defaultPositionalThreshold,
             velocityThreshold = defaultVelocityThreshold,
-            confirmValueChange = {
-                counter++
-                false
-            }
+            animationSpec = defaultAnimationSpec
         )
-        state.updateAnchors(mapOf(A to 0f, B to 200f, C to 300f))
-        state.anchoredDrag {
-            // should be B
-            dragTo(200f)
-        }
-
-        assertThat(counter).isEqualTo(0)
-        assertThat(state.currentValue).isEqualTo(B)
+        assertThat(state.anchors).isEqualTo(anchors)
+        assertThat(state.offset).isEqualTo(initialValueOffset)
     }
 
     @Test
-    fun anchoredDraggable_customDrag_noAnchor_doesntCallConfirm() = runBlocking {
-
-        var counter: Int = 0
-
+    fun anchoredDraggable_constructorWithAnchors_initialValueNotInAnchors_updatesCurrentValue() {
+        val anchors = DraggableAnchors { B at 200f }
         val state = AnchoredDraggableState(
             initialValue = A,
+            anchors = anchors,
             positionalThreshold = defaultPositionalThreshold,
             velocityThreshold = defaultVelocityThreshold,
-            confirmValueChange = {
-                counter++
-                false
-            }
+            animationSpec = defaultAnimationSpec
         )
-        state.updateAnchors(mapOf(A to 0f, B to 200f))
-        state.anchoredDrag(targetValue = C) {
-            // no op, doesn't matter
-        }
-
-        assertThat(counter).isEqualTo(0)
-        assertThat(state.currentValue).isEqualTo(C)
+        assertThat(state.anchors).isEqualTo(anchors)
+        assertThat(state.offset).isNaN()
     }
 
-    @Test
-    fun anchoredDraggable_updateAnchors_ongoingOffsetMutation_shouldNotUpdate() = runBlocking {
-        val clock = HandPumpTestFrameClock()
-        val animationScope = CoroutineScope(clock)
-        val animationDuration = 2000
-
-        var anchorChangeHandlerInvoked = false
-        val testAnchorChangedCallback =
-            AnchorChangedCallback<AnchoredDraggableTestValue> { _, _, _ ->
-                anchorChangeHandlerInvoked = true
-            }
-        val state = AnchoredDraggableState(
-            initialValue = A,
-            animationSpec = tween(animationDuration),
-            positionalThreshold = defaultPositionalThreshold,
-            velocityThreshold = defaultVelocityThreshold
-        )
-        val anchors = mapOf(A to 0f, B to 200f, C to 300f)
-
-        state.updateAnchors(anchors, testAnchorChangedCallback)
-        animationScope.launch(start = CoroutineStart.UNDISPATCHED) {
-            state.animateTo(B)
-        }
-        clock.advanceByFrame()
-
-        assertThat(state.isAnimationRunning).isTrue()
-
-        val offsetBeforeAnchorUpdate = state.offset
-        state.updateAnchors(mapOf(A to 100f, B to 500f, C to 700f), testAnchorChangedCallback)
-        assertThat(offsetBeforeAnchorUpdate).isEqualTo(state.offset)
-        assertThat(anchorChangeHandlerInvoked).isTrue()
-    }
+    private suspend fun suspendIndefinitely() = suspendCancellableCoroutine<Unit> { }
 
     private class HandPumpTestFrameClock : MonotonicFrameClock {
         private val frameCh = Channel<Long>(1)
@@ -936,4 +980,6 @@
     }
 
     private val defaultVelocityThreshold: () -> Float = { with(rule.density) { 125.dp.toPx() } }
+
+    private val defaultAnimationSpec = tween<Float>()
 }
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
index 1d4b089..0f85c18 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AnchoredDraggable.kt
@@ -26,27 +26,116 @@
 import androidx.compose.foundation.gestures.draggable
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.offset
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
-import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.saveable.Saver
-import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
 import androidx.compose.runtime.structuralEqualityPolicy
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.dp
 import kotlin.math.abs
 import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 
 /**
+ * Structure that represents the anchors of a [AnchoredDraggableState].
+ *
+ * See the DraggableAnchors factory method to construct drag anchors using a default implementation.
+ */
+@ExperimentalMaterialApi
+internal interface DraggableAnchors<T> {
+
+    /**
+     * Get the anchor position for an associated [value]
+     *
+     * @return The position of the anchor, or [Float.NaN] if the anchor does not exist
+     */
+    fun positionOf(value: T): Float
+
+    /**
+     * Whether there is an anchor position associated with the [value]
+     *
+     * @param value The value to look up
+     * @return true if there is an anchor for this value, false if there is no anchor for this value
+     */
+    fun hasAnchorFor(value: T): Boolean
+
+    /**
+     * Find the closest anchor to the [position].
+     *
+     * @param position The position to start searching from
+     *
+     * @return The closest anchor or null if the anchors are empty
+     */
+    fun closestAnchor(position: Float): T?
+
+    /**
+     * Find the closest anchor to the [position], in the specified direction.
+     *
+     * @param position The position to start searching from
+     * @param searchUpwards Whether to search upwards from the current position or downwards
+     *
+     * @return The closest anchor or null if the anchors are empty
+     */
+    fun closestAnchor(position: Float, searchUpwards: Boolean): T?
+
+    /**
+     * The smallest anchor, or [Float.NEGATIVE_INFINITY] if the anchors are empty.
+     */
+    fun minAnchor(): Float
+
+    /**
+     * The biggest anchor, or [Float.POSITIVE_INFINITY] if the anchors are empty.
+     */
+    fun maxAnchor(): Float
+
+    /**
+     * The amount of anchors
+     */
+    val size: Int
+}
+
+/**
+ * [DraggableAnchorsConfig] stores a mutable configuration anchors, comprised of values of [T] and
+ * corresponding [Float] positions. This [DraggableAnchorsConfig] is used to construct an immutable
+ * [DraggableAnchors] instance later on.
+ */
+@ExperimentalMaterialApi
+internal class DraggableAnchorsConfig<T> {
+
+    internal val anchors = mutableMapOf<T, Float>()
+
+    /**
+     * Set the anchor position for [this] anchor.
+     *
+     * @param position The anchor position.
+     */
+    @Suppress("BuilderSetStyle")
+    infix fun T.at(position: Float) {
+        anchors[this] = position
+    }
+}
+
+/**
+ * Create a new [DraggableAnchors] instance using a builder function.
+ *
+ * @param builder A function with a [DraggableAnchorsConfig] that offers APIs to configure anchors
+ * @return A new [DraggableAnchors] instance with the anchor positions set by the `builder`
+ * function.
+ */
+@ExperimentalMaterialApi
+internal fun <T : Any> DraggableAnchors(
+    builder: DraggableAnchorsConfig<T>.() -> Unit
+): DraggableAnchors<T> = MapDraggableAnchors(DraggableAnchorsConfig<T>().apply(builder).anchors)
+
+/**
  * Enable drag gestures between a set of predefined values.
  *
  * When a drag is detected, the offset of the [AnchoredDraggableState] will be updated with the drag
@@ -89,6 +178,7 @@
  * @see [AnchoredDraggableState.anchoredDrag] to learn how to start the anchored drag and get the
  * access to this scope.
  */
+@ExperimentalMaterialApi
 internal interface AnchoredDragScope {
     /**
      * Assign a new value for an offset value for [AnchoredDraggableState].
@@ -104,14 +194,13 @@
 
 /**
  * State of the [anchoredDraggable] modifier.
+ * Use the constructor overload with anchors if the anchors are defined in composition, or update
+ * the anchors using [updateAnchors].
  *
  * This contains necessary information about any ongoing drag or animation and provides methods
- * to change the state either immediately or by starting an animation. To create and remember a
- * [AnchoredDraggableState] use [rememberAnchoredDraggableState].
+ * to change the state either immediately or by starting an animation.
  *
  * @param initialValue The initial value of the state.
- * @param animationSpec The default animation that will be used to animate to a new state.
- * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
  * @param positionalThreshold The positional threshold, in px, to be used when calculating the
  * target state while a drag is in progress and when settling after the drag ends. This is the
  * distance from the start of a transition. It will be, depending on the direction of the
@@ -119,6 +208,8 @@
  * @param velocityThreshold The velocity threshold (in px per second) that the end velocity has to
  * exceed in order to animate to the next state, even if the [positionalThreshold] has not been
  * reached.
+ * @param animationSpec The default animation that will be used to animate to a new state.
+ * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
  */
 @Stable
 @ExperimentalMaterialApi
@@ -128,10 +219,48 @@
     internal val positionalThreshold: (totalDistance: Float) -> Float,
     @Suppress("PrimitiveInLambda")
     internal val velocityThreshold: () -> Float,
-    val animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
+    val animationSpec: AnimationSpec<Float>,
     internal val confirmValueChange: (newValue: T) -> Boolean = { true }
 ) {
 
+    /**
+     * Construct an [AnchoredDraggableState] instance with anchors.
+     *
+     * @param initialValue The initial value of the state.
+     * @param anchors The anchors of the state. Use [updateAnchors] to update the anchors later.
+     * @param animationSpec The default animation that will be used to animate to a new state.
+     * @param confirmValueChange Optional callback invoked to confirm or veto a pending state
+     * change.
+     * @param positionalThreshold The positional threshold, in px, to be used when calculating the
+     * target state while a drag is in progress and when settling after the drag ends. This is the
+     * distance from the start of a transition. It will be, depending on the direction of the
+     * interaction, added or subtracted from/to the origin offset. It should always be a positive
+     * value.
+     * @param velocityThreshold The velocity threshold (in px per second) that the end velocity has
+     * to exceed in order to animate to the next state, even if the [positionalThreshold] has not
+     * been reached.
+     */
+    @ExperimentalMaterialApi
+    constructor(
+        initialValue: T,
+        anchors: DraggableAnchors<T>,
+        @Suppress("PrimitiveInLambda")
+        positionalThreshold: (totalDistance: Float) -> Float,
+        @Suppress("PrimitiveInLambda")
+        velocityThreshold: () -> Float,
+        animationSpec: AnimationSpec<Float>,
+        confirmValueChange: (newValue: T) -> Boolean = { true }
+    ) : this(
+        initialValue,
+        positionalThreshold,
+        velocityThreshold,
+        animationSpec,
+        confirmValueChange
+    ) {
+        this.anchors = anchors
+        trySnapTo(initialValue)
+    }
+
     private val dragMutex = InternalMutatorMutex()
 
     internal val draggableState = object : DraggableState {
@@ -170,7 +299,7 @@
      * will be the current value.
      */
     val targetValue: T by derivedStateOf {
-        animationTarget ?: run {
+        dragTarget ?: run {
             val currentOffset = offset
             if (!currentOffset.isNaN()) {
                 computeTarget(currentOffset, currentValue, velocity = 0f)
@@ -184,7 +313,7 @@
      * specified).
      */
     internal val closestValue: T by derivedStateOf {
-        animationTarget ?: run {
+        dragTarget ?: run {
             val currentOffset = offset
             if (!currentOffset.isNaN()) {
                 computeTargetWithoutThresholds(currentOffset, currentValue)
@@ -221,7 +350,7 @@
     /**
      * Whether an animation is currently in progress.
      */
-    val isAnimationRunning: Boolean get() = animationTarget != null
+    val isAnimationRunning: Boolean get() = dragTarget != null
 
     /**
      * The fraction of the progress going from [currentValue] to [closestValue], within [0f..1f]
@@ -229,15 +358,15 @@
      */
     /*@FloatRange(from = 0f, to = 1f)*/
     val progress: Float by derivedStateOf(structuralEqualityPolicy()) {
-            val a = anchors[currentValue] ?: 0f
-            val b = anchors[closestValue] ?: 0f
-            val distance = abs(b - a)
-            if (distance > 1e-6f) {
-                val progress = (this.requireOffset() - a) / (b - a)
-                // If we are very close to 0f or 1f, we round to the closest
-                if (progress < 1e-6f) 0f else if (progress > 1 - 1e-6f) 1f else progress
-            } else 1f
-        }
+        val a = anchors.positionOf(currentValue)
+        val b = anchors.positionOf(closestValue)
+        val distance = abs(b - a)
+        if (!distance.isNaN() && distance > 1e-6f) {
+            val progress = (this.requireOffset() - a) / (b - a)
+            // If we are very close to 0f or 1f, we round to the closest
+            if (progress < 1e-6f) 0f else if (progress > 1 - 1e-6f) 1f else progress
+        } else 1f
+    }
 
     /**
      * The velocity of the last known animation. Gets reset to 0f when an animation completes
@@ -248,68 +377,52 @@
     var lastVelocity: Float by mutableFloatStateOf(0f)
         private set
 
-    /**
-     * The minimum offset this state can reach. This will be the smallest anchor, or
-     * [Float.NEGATIVE_INFINITY] if the anchors are not initialized yet.
-     */
-    val minOffset by derivedStateOf { anchors.minOrNull() ?: Float.NEGATIVE_INFINITY }
+    private var dragTarget: T? by mutableStateOf(null)
+
+    var anchors: DraggableAnchors<T> by mutableStateOf(emptyDraggableAnchors())
+        private set
 
     /**
-     * The maximum offset this state can reach. This will be the biggest anchor, or
-     * [Float.POSITIVE_INFINITY] if the anchors are not initialized yet.
-     */
-    val maxOffset by derivedStateOf { anchors.maxOrNull() ?: Float.POSITIVE_INFINITY }
-
-    private var animationTarget: T? by mutableStateOf(null)
-
-    internal var anchors by mutableStateOf(emptyMap<T, Float>())
-
-    /**
-     * Update the anchors.
-     * If the previous set of anchors was empty, attempt to update the offset to match the initial
-     * value's anchor. If the [newAnchors] are different to the existing anchors, or there is no
-     * anchor for the [currentValue], the [onAnchorsChanged] callback will be invoked.
+     * Update the anchors. If there is no ongoing [anchoredDrag] operation, snap to the [newTarget],
+     * otherwise restart the ongoing [anchoredDrag] operation (e.g. an animation) with the new
+     * anchors.
      *
      * <b>If your anchors depend on the size of the layout, updateAnchors should be called in the
      * layout (placement) phase, e.g. through Modifier.onSizeChanged.</b> This ensures that the
      * state is set up within the same frame.
-     * For static anchors, or anchors with different data dependencies, updateAnchors is safe to be
-     * called any time, for example from a side effect.
+     * For static anchors, or anchors with different data dependencies, [updateAnchors] is safe to
+     * be called from side effects or layout.
      *
-     * @param newAnchors The new anchors
-     * @param onAnchorsChanged Optional callback to be invoked if the state needs to be updated
-     * after updating the anchors, for example if the anchor for the [currentValue] has been removed
+     * @param newAnchors The new anchors.
+     * @param newTarget The new target, by default the closest anchor or the current target if there
+     * are no anchors.
      */
-    internal fun updateAnchors(
-        newAnchors: Map<T, Float>,
-        onAnchorsChanged: AnchorChangedCallback<T>? = null
+    fun updateAnchors(
+        newAnchors: DraggableAnchors<T>,
+        newTarget: T = if (!offset.isNaN()) {
+            newAnchors.closestAnchor(offset) ?: targetValue
+        } else targetValue
     ) {
         if (anchors != newAnchors) {
-            val previousAnchors = anchors
-            val previousTarget = targetValue
-            val previousAnchorsEmpty = anchors.isEmpty()
             anchors = newAnchors
-
-            val currentValueHasAnchor = anchors[currentValue] != null
-            if (previousAnchorsEmpty && currentValueHasAnchor) {
-                trySnapTo(currentValue)
-            } else {
-                onAnchorsChanged?.onAnchorsChanged(
-                    previousTargetValue = previousTarget,
-                    previousAnchors = previousAnchors,
-                    newAnchors = newAnchors
-                )
+            // Attempt to snap. If nobody is holding the lock, we can immediately update the offset.
+            // If anybody is holding the lock, we send a signal to restart the ongoing work with the
+            // updated anchors.
+            val snapSuccessful = trySnapTo(newTarget)
+            if (!snapSuccessful) {
+                dragTarget = newTarget
             }
         }
     }
 
     /**
-     * Whether the [value] has an anchor associated with it.
-     */
-    fun hasAnchorForValue(value: T): Boolean = anchors.containsKey(value)
-
-    /**
-     * Find the closest anchor taking into account the velocity and settle at it with an animation.
+     * Find the closest anchor, taking into account the [velocityThreshold] and
+     * [positionalThreshold], and settle at it with an animation.
+     *
+     * If the [velocity] is lower than the [velocityThreshold], the closest anchor by distance and
+     * [positionalThreshold] will be the target. If the [velocity] is higher than the
+     * [velocityThreshold], the [positionalThreshold] will <b>not</b> be considered and the next
+     * anchor in the direction indicated by the sign of the [velocity] will be the target.
      */
     suspend fun settle(velocity: Float) {
         val previousValue = this.currentValue
@@ -332,30 +445,30 @@
         velocity: Float
     ): T {
         val currentAnchors = anchors
-        val currentAnchor = currentAnchors[currentValue]
+        val currentAnchorPosition = currentAnchors.positionOf(currentValue)
         val velocityThresholdPx = velocityThreshold()
-        return if (currentAnchor == offset || currentAnchor == null) {
+        return if (currentAnchorPosition == offset || currentAnchorPosition.isNaN()) {
             currentValue
-        } else if (currentAnchor < offset) {
+        } else if (currentAnchorPosition < offset) {
             // Swiping from lower to upper (positive).
             if (velocity >= velocityThresholdPx) {
-                currentAnchors.closestAnchor(offset, true)
+                currentAnchors.closestAnchor(offset, true)!!
             } else {
-                val upper = currentAnchors.closestAnchor(offset, true)
-                val distance = abs(currentAnchors.getValue(upper) - currentAnchor)
+                val upper = currentAnchors.closestAnchor(offset, true)!!
+                val distance = abs(currentAnchors.positionOf(upper) - currentAnchorPosition)
                 val relativeThreshold = abs(positionalThreshold(distance))
-                val absoluteThreshold = abs(currentAnchor + relativeThreshold)
+                val absoluteThreshold = abs(currentAnchorPosition + relativeThreshold)
                 if (offset < absoluteThreshold) currentValue else upper
             }
         } else {
             // Swiping from upper to lower (negative).
             if (velocity <= -velocityThresholdPx) {
-                currentAnchors.closestAnchor(offset, false)
+                currentAnchors.closestAnchor(offset, false)!!
             } else {
-                val lower = currentAnchors.closestAnchor(offset, false)
-                val distance = abs(currentAnchor - currentAnchors.getValue(lower))
+                val lower = currentAnchors.closestAnchor(offset, false)!!
+                val distance = abs(currentAnchorPosition - currentAnchors.positionOf(lower))
                 val relativeThreshold = abs(positionalThreshold(distance))
-                val absoluteThreshold = abs(currentAnchor - relativeThreshold)
+                val absoluteThreshold = abs(currentAnchorPosition - relativeThreshold)
                 if (offset < 0) {
                     // For negative offsets, larger absolute thresholds are closer to lower anchors
                     // than smaller ones.
@@ -372,13 +485,13 @@
         currentValue: T,
     ): T {
         val currentAnchors = anchors
-        val currentAnchor = currentAnchors[currentValue]
-        return if (currentAnchor == offset || currentAnchor == null) {
+        val currentAnchorPosition = currentAnchors.positionOf(currentValue)
+        return if (currentAnchorPosition == offset || currentAnchorPosition.isNaN()) {
             currentValue
-        } else if (currentAnchor < offset) {
-            currentAnchors.closestAnchor(offset, true)
+        } else if (currentAnchorPosition < offset) {
+            currentAnchors.closestAnchor(offset, true) ?: currentValue
         } else {
-            currentAnchors.closestAnchor(offset, false)
+            currentAnchors.closestAnchor(offset, false) ?: currentValue
         }
     }
 
@@ -390,25 +503,44 @@
     }
 
     /**
-     * Call this function to take control of drag logic and perform anchored drag.
+     * Call this function to take control of drag logic and perform anchored drag with the latest
+     * anchors.
      *
      * All actions that change the [offset] of this [AnchoredDraggableState] must be performed
      * within an [anchoredDrag] block (even if they don't call any other methods on this object)
      * in order to guarantee that mutual exclusion is enforced.
      *
      * If [anchoredDrag] is called from elsewhere with the [dragPriority] higher or equal to ongoing
-     * drag, ongoing drag will be canceled.
+     * drag, the ongoing drag will be cancelled.
+     *
+     * <b>If the [anchors] change while the [block] is being executed, it will be cancelled and
+     * re-executed with the latest anchors and target.</b> This allows you to target the correct
+     * state.
      *
      * @param dragPriority of the drag operation
      * @param block perform anchored drag given the current anchor provided
      */
     suspend fun anchoredDrag(
         dragPriority: MutatePriority = MutatePriority.Default,
-        block: suspend AnchoredDragScope.(anchors: Map<T, Float>) -> Unit
-    ): Unit = doAnchoredDrag(null, dragPriority, block)
+        block: suspend AnchoredDragScope.(anchors: DraggableAnchors<T>) -> Unit
+    ) {
+        try {
+            dragMutex.mutate(dragPriority) {
+                restartable(inputs = { anchors }) { latestAnchors ->
+                    anchoredDragScope.block(latestAnchors)
+                }
+            }
+        } finally {
+            val closest = anchors.closestAnchor(offset)
+            if (closest != null && abs(offset - anchors.positionOf(closest)) <= 0.5f) {
+                currentValue = closest
+            }
+        }
+    }
 
     /**
-     * Call this function to take control of drag logic and perform anchored drag.
+     * Call this function to take control of drag logic and perform anchored drag with the latest
+     * anchors and target.
      *
      * All actions that change the [offset] of this [AnchoredDraggableState] must be performed
      * within an [anchoredDrag] block (even if they don't call any other methods on this object)
@@ -418,8 +550,12 @@
      * to arrive to. This will set [AnchoredDraggableState.targetValue] to provided value so
      * consumers can reflect it in their UIs.
      *
+     * <b>If the [anchors] or [AnchoredDraggableState.targetValue] change while the [block] is being
+     * executed, it will be cancelled and re-executed with the latest anchors and target.</b> This
+     * allows you to target the correct state.
+     *
      * If [anchoredDrag] is called from elsewhere with the [dragPriority] higher or equal to ongoing
-     * drag, ongoing drag will be canceled.
+     * drag, the ongoing drag will be cancelled.
      *
      * @param targetValue hint the target value that this [anchoredDrag] is intended to arrive to
      * @param dragPriority of the drag operation
@@ -428,39 +564,34 @@
     suspend fun anchoredDrag(
         targetValue: T,
         dragPriority: MutatePriority = MutatePriority.Default,
-        block: suspend AnchoredDragScope.(anchors: Map<T, Float>) -> Unit
-    ): Unit = doAnchoredDrag(targetValue, dragPriority, block)
-
-    private suspend fun doAnchoredDrag(
-        targetValue: T?,
-        dragPriority: MutatePriority,
-        block: suspend AnchoredDragScope.(anchors: Map<T, Float>) -> Unit
-    ) = coroutineScope {
-        if (targetValue == null || anchors.containsKey(targetValue)) {
+        block: suspend AnchoredDragScope.(anchors: DraggableAnchors<T>, targetValue: T) -> Unit
+    ) {
+        if (anchors.hasAnchorFor(targetValue)) {
             try {
                 dragMutex.mutate(dragPriority) {
-                    if (targetValue != null) animationTarget = targetValue
-                    anchoredDragScope.block(anchors)
+                    dragTarget = targetValue
+                    restartable(
+                        inputs = { anchors to this@AnchoredDraggableState.targetValue }
+                    ) { (latestAnchors, latestTarget) ->
+                        anchoredDragScope.block(latestAnchors, latestTarget)
+                    }
                 }
             } finally {
-                if (targetValue != null) animationTarget = null
-                val endState =
-                    anchors
-                        .entries
-                        .firstOrNull { (_, anchorOffset) -> abs(anchorOffset - offset) < 0.5f }
-                        ?.key
-
-                if (endState != null) {
-                    currentValue = endState
+                dragTarget = null
+                val closest = anchors.closestAnchor(offset)
+                if (closest != null && abs(offset - anchors.positionOf(closest)) <= 0.5f) {
+                    currentValue = closest
                 }
             }
         } else {
+            // Todo: b/283467401, revisit this behavior
             currentValue = targetValue
         }
     }
 
     internal fun newOffsetForDelta(delta: Float) =
-        ((if (offset.isNaN()) 0f else offset) + delta).coerceIn(minOffset, maxOffset)
+        ((if (offset.isNaN()) 0f else offset) + delta)
+            .coerceIn(anchors.minAnchor(), anchors.maxAnchor())
 
     /**
      * Drag by the [delta], coerce it in the bounds and dispatch it to the [AnchoredDraggableState].
@@ -481,12 +612,12 @@
      *
      * @return true if the synchronous snap was successful, or false if we couldn't snap synchronous
      */
-    internal fun trySnapTo(targetValue: T): Boolean = dragMutex.tryMutate {
+    private fun trySnapTo(targetValue: T): Boolean = dragMutex.tryMutate {
         with(anchoredDragScope) {
-            val targetOffset = anchors[targetValue]
-            if (targetOffset != null) {
+            val targetOffset = anchors.positionOf(targetValue)
+            if (!targetOffset.isNaN()) {
                 dragTo(targetOffset)
-                animationTarget = null
+                dragTarget = null
             }
             currentValue = targetValue
         }
@@ -504,7 +635,7 @@
             @Suppress("PrimitiveInLambda")
             positionalThreshold: (distance: Float) -> Float,
             @Suppress("PrimitiveInLambda")
-            velocityThreshold: () -> Float
+            velocityThreshold: () -> Float,
         ) = Saver<AnchoredDraggableState<T>, T>(
             save = { it.currentValue },
             restore = {
@@ -518,34 +649,6 @@
             }
         )
     }
-
-    /**
-     * Defines a callback that is invoked when the anchors have changed.
-     *
-     * Components with custom reconciliation logic should implement this callback, for example to
-     * re-target an in-progress animation when the anchors change.
-     *
-     * @see AnchoredDraggableDefaults.ReconcileAnimationOnAnchorChangedCallback for a default
-     * implementation
-     */
-    @ExperimentalMaterialApi
-    fun interface AnchorChangedCallback<T> {
-
-        /**
-         * Callback that is invoked when the anchors have changed, after the
-         * [AnchoredDraggableState] has been updated with them. Use this hook to re-launch
-         * animations or interrupt them if needed.
-         *
-         * @param previousTargetValue The target value before the anchors were updated
-         * @param previousAnchors The previously set anchors
-         * @param newAnchors The newly set anchors
-         */
-        fun onAnchorsChanged(
-            previousTargetValue: T,
-            previousAnchors: Map<T, Float>,
-            newAnchors: Map<T, Float>,
-        )
-    }
 }
 
 /**
@@ -560,9 +663,9 @@
  */
 @ExperimentalMaterialApi
 internal suspend fun <T> AnchoredDraggableState<T>.snapTo(targetValue: T) {
-    anchoredDrag(targetValue = targetValue) { anchors ->
-        val targetOffset = anchors[targetValue]
-        if (targetOffset != null) dragTo(targetOffset)
+    anchoredDrag(targetValue = targetValue) { anchors, latestTarget ->
+        val targetOffset = anchors.positionOf(latestTarget)
+        if (!targetOffset.isNaN()) dragTo(targetOffset)
     }
 }
 
@@ -582,9 +685,9 @@
     targetValue: T,
     velocity: Float = this.lastVelocity,
 ) {
-    anchoredDrag(targetValue = targetValue) { anchors ->
-        val targetOffset = anchors[targetValue]
-        if (targetOffset != null) {
+    anchoredDrag(targetValue = targetValue) { anchors, latestTarget ->
+        val targetOffset = anchors.positionOf(latestTarget)
+        if (!targetOffset.isNaN()) {
             var prev = if (offset.isNaN()) 0f else offset
             animate(prev, targetOffset, velocity, animationSpec) { value, velocity ->
                 // Our onDrag coerces the value within the bounds, but an animation may
@@ -599,43 +702,6 @@
 }
 
 /**
- * Create and remember a [AnchoredDraggableState].
- *
- * @param initialValue The initial value.
- * @param animationSpec The default animation that will be used to animate to a new value.
- * @param confirmValueChange Optional callback invoked to confirm or veto a pending value change.
- */
-@Composable
-@ExperimentalMaterialApi
-internal fun <T : Any> rememberAnchoredDraggableState(
-    initialValue: T,
-    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
-    confirmValueChange: (newValue: T) -> Boolean = { true }
-): AnchoredDraggableState<T> {
-    @Suppress("PrimitiveInLambda")
-    val positionalThreshold = AnchoredDraggableDefaults.positionalThreshold
-    @Suppress("PrimitiveInLambda")
-    val velocityThreshold = AnchoredDraggableDefaults.velocityThreshold
-    return rememberSaveable(
-        initialValue, animationSpec, confirmValueChange, positionalThreshold, velocityThreshold,
-        saver = AnchoredDraggableState.Saver(
-            animationSpec = animationSpec,
-            confirmValueChange = confirmValueChange,
-            positionalThreshold = positionalThreshold,
-            velocityThreshold = velocityThreshold
-        ),
-    ) {
-        AnchoredDraggableState(
-            initialValue = initialValue,
-            animationSpec = animationSpec,
-            confirmValueChange = confirmValueChange,
-            positionalThreshold = positionalThreshold,
-            velocityThreshold = velocityThreshold
-        )
-    }
-}
-
-/**
  * Contains useful defaults for [anchoredDraggable] and [AnchoredDraggableState].
  */
 @Stable
@@ -648,69 +714,73 @@
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @ExperimentalMaterialApi
     val AnimationSpec = SpringSpec<Float>()
+}
 
-    /**
-     * The default velocity threshold (1.8 dp per millisecond) used by
-     * [rememberAnchoredDraggableState].
-     */
-    @get:ExperimentalMaterialApi
-    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-    @ExperimentalMaterialApi
-    val velocityThreshold: () -> Float
-        @Suppress("PrimitiveInLambda")
-        @Composable get() = with(LocalDensity.current) { { 125.dp.toPx() } }
-
-    /**
-     * The default positional threshold (56 dp) used by [rememberAnchoredDraggableState]
-     */
-    @get:ExperimentalMaterialApi
-    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-    @ExperimentalMaterialApi
-    val positionalThreshold: (totalDistance: Float) -> Float
-        @Suppress("PrimitiveInLambda")
-        @Composable get() = with(LocalDensity.current) {
-            { 56.dp.toPx() }
-        }
-
-    /**
-     * A [AnchorChangedCallback] implementation that attempts to reconcile an in-progress animation
-     * by re-targeting it if necessary or finding the closest new anchor.
-     * If the previous anchor is not in the new set of anchors, this implementation will snap to the
-     * closest anchor.
-     *
-     * Consider implementing a custom handler for more complex components like sheets.
-     */
-    @ExperimentalMaterialApi
-    internal fun <T> ReconcileAnimationOnAnchorChangedCallback(
-        state: AnchoredDraggableState<T>,
-        scope: CoroutineScope
-    ) = AnchorChangedCallback<T> { previousTarget, previousAnchors, newAnchors ->
-        val previousTargetOffset = previousAnchors[previousTarget]
-        val newTargetOffset = newAnchors[previousTarget]
-        if (previousTargetOffset != newTargetOffset) {
-            if (newTargetOffset != null) {
-                scope.launch {
-                    state.animateTo(previousTarget, state.lastVelocity)
-                }
-            } else {
-                scope.launch {
-                    state.snapTo(newAnchors.closestAnchor(offset = state.requireOffset()))
-                }
-            }
-        }
+private class AnchoredDragFinishedSignal : CancellationException() {
+    override fun fillInStackTrace(): Throwable {
+        stackTrace = emptyArray()
+        return this
     }
 }
 
-private fun <T> Map<T, Float>.closestAnchor(
-    offset: Float = 0f,
-    searchUpwards: Boolean = false
-): T {
-    require(isNotEmpty()) { "The anchors were empty when trying to find the closest anchor" }
-    return minBy { (_, anchor) ->
-        val delta = if (searchUpwards) anchor - offset else offset - anchor
-        if (delta < 0) Float.POSITIVE_INFINITY else delta
-    }.key
+private suspend fun <I> restartable(inputs: () -> I, block: suspend (I) -> Unit) {
+    try {
+        coroutineScope {
+            var previousDrag: Job? = null
+            snapshotFlow(inputs)
+                .collect { latestInputs ->
+                    previousDrag?.apply {
+                        cancel(AnchoredDragFinishedSignal())
+                        join()
+                    }
+                    previousDrag = launch(start = CoroutineStart.UNDISPATCHED) {
+                        block(latestInputs)
+                        this@coroutineScope.cancel(AnchoredDragFinishedSignal())
+                    }
+                }
+        }
+    } catch (anchoredDragFinished: AnchoredDragFinishedSignal) {
+        // Ignored
+    }
 }
 
-private fun <T> Map<T, Float>.minOrNull() = minOfOrNull { (_, offset) -> offset }
-private fun <T> Map<T, Float>.maxOrNull() = maxOfOrNull { (_, offset) -> offset }
+private fun <T> emptyDraggableAnchors() = MapDraggableAnchors<T>(emptyMap())
+
+@OptIn(ExperimentalMaterialApi::class)
+private class MapDraggableAnchors<T>(private val anchors: Map<T, Float>) : DraggableAnchors<T> {
+
+    override fun positionOf(value: T): Float = anchors[value] ?: Float.NaN
+    override fun hasAnchorFor(value: T) = anchors.containsKey(value)
+
+    override fun closestAnchor(position: Float): T? = anchors.minByOrNull {
+        abs(position - it.value)
+    }?.key
+
+    override fun closestAnchor(
+        position: Float,
+        searchUpwards: Boolean
+    ): T? {
+        return anchors.minByOrNull { (_, anchor) ->
+            val delta = if (searchUpwards) anchor - position else position - anchor
+            if (delta < 0) Float.POSITIVE_INFINITY else delta
+        }?.key
+    }
+
+    override fun minAnchor() = anchors.values.minOrNull() ?: Float.NaN
+
+    override fun maxAnchor() = anchors.values.maxOrNull() ?: Float.NaN
+
+    override val size: Int
+        get() = anchors.size
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is MapDraggableAnchors<*>) return false
+
+        return anchors == other.anchors
+    }
+
+    override fun hashCode() = 31 * anchors.hashCode()
+
+    override fun toString() = "MapDraggableAnchors($anchors)"
+}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BackdropScaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BackdropScaffold.kt
index 3453f601..5a79071 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BackdropScaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BackdropScaffold.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("Deprecation") // b/274465184
+
 package androidx.compose.material
 
 import androidx.compose.animation.core.AnimationSpec
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
index 854ebb4..1e173af 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomSheetScaffold.kt
@@ -23,7 +23,6 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredHeightIn
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
 import androidx.compose.material.BottomSheetValue.Collapsed
 import androidx.compose.material.BottomSheetValue.Expanded
 import androidx.compose.runtime.Composable
@@ -55,7 +54,6 @@
 import androidx.compose.ui.util.fastMaxBy
 import kotlin.math.roundToInt
 import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 
 /**
@@ -86,7 +84,7 @@
 @ExperimentalMaterialApi
 fun BottomSheetScaffoldState(
     initialValue: BottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmStateChange: (BottomSheetValue) -> Boolean
 ) = BottomSheetState(
     initialValue = initialValue,
@@ -108,7 +106,7 @@
 fun BottomSheetState(
     initialValue: BottomSheetValue,
     density: Density,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmValueChange: (BottomSheetValue) -> Boolean = { true }
 ) = BottomSheetState(initialValue, animationSpec, confirmValueChange).also {
     it.density = density
@@ -138,7 +136,7 @@
     )
 ) constructor(
     initialValue: BottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmValueChange: (BottomSheetValue) -> Boolean = { true }
 ) {
 
@@ -201,7 +199,11 @@
      * This method will throw [CancellationException] if the animation is interrupted.
      */
     suspend fun expand() {
-        val target = if (anchoredDraggableState.hasAnchorForValue(Expanded)) Expanded else Collapsed
+        val target = if (anchoredDraggableState.anchors.hasAnchorFor(Expanded)) {
+            Expanded
+        } else {
+            Collapsed
+        }
         anchoredDraggableState.animateTo(target)
     }
 
@@ -232,10 +234,6 @@
 
     internal suspend fun snapTo(target: BottomSheetValue) = anchoredDraggableState.snapTo(target)
 
-    internal fun trySnapTo(target: BottomSheetValue) = anchoredDraggableState.trySnapTo(target)
-
-    internal val isAnimationRunning: Boolean get() = anchoredDraggableState.isAnimationRunning
-
     internal var density: Density? = null
     private fun requireDensity() = requireNotNull(density) {
         "The density on BottomSheetState ($this) was not set. Did you use BottomSheetState with " +
@@ -303,7 +301,7 @@
 @ExperimentalMaterialApi
 fun rememberBottomSheetState(
     initialValue: BottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmStateChange: (BottomSheetValue) -> Boolean = { true }
 ): BottomSheetState {
     val density = LocalDensity.current
@@ -469,14 +467,11 @@
                         .requiredHeightIn(min = sheetPeekHeight),
                     calculateAnchors = { sheetSize ->
                         val sheetHeight = sheetSize.height.toFloat()
-                        val collapsedHeight = layoutHeight - peekHeightPx
-                        if (sheetHeight == 0f || sheetHeight == peekHeightPx) {
-                            mapOf(Collapsed to collapsedHeight)
-                        } else {
-                            mapOf(
-                                Collapsed to collapsedHeight,
-                                Expanded to layoutHeight - sheetHeight
-                            )
+                        DraggableAnchors {
+                            Collapsed at layoutHeight - peekHeightPx
+                            if (sheetHeight > 0f && sheetHeight != peekHeightPx) {
+                                Expanded at layoutHeight - sheetHeight
+                            }
                         }
                     },
                     sheetBackgroundColor = sheetBackgroundColor,
@@ -526,7 +521,7 @@
 private fun BottomSheet(
     state: BottomSheetState,
     sheetGesturesEnabled: Boolean,
-    calculateAnchors: (sheetSize: IntSize) -> Map<BottomSheetValue, Float>,
+    calculateAnchors: (sheetSize: IntSize) -> DraggableAnchors<BottomSheetValue>,
     sheetShape: Shape,
     sheetElevation: Dp,
     sheetBackgroundColor: Color,
@@ -535,9 +530,6 @@
     content: @Composable ColumnScope.() -> Unit
 ) {
     val scope = rememberCoroutineScope()
-    val anchorChangeCallback = remember(state, scope) {
-        BottomSheetScaffoldAnchorChangeCallback(state, scope)
-    }
     Surface(
         modifier
             .anchoredDraggable(
@@ -546,10 +538,12 @@
                 enabled = sheetGesturesEnabled,
             )
             .onSizeChanged { layoutSize ->
-                state.anchoredDraggableState.updateAnchors(
-                    newAnchors = calculateAnchors(layoutSize),
-                    onAnchorsChanged = anchorChangeCallback
-                )
+                val newAnchors = calculateAnchors(layoutSize)
+                val newTarget = when (state.anchoredDraggableState.targetValue) {
+                    Collapsed -> Collapsed
+                    Expanded -> if (newAnchors.hasAnchorFor(Expanded)) Expanded else Collapsed
+                }
+                state.anchoredDraggableState.updateAnchors(newAnchors, newTarget)
             }
             .semantics {
                 // If we don't have anchors yet, or have only one anchor we don't want any
@@ -696,7 +690,7 @@
     override suspend fun onPreFling(available: Velocity): Velocity {
         val toFling = available.toFloat()
         val currentOffset = state.requireOffset()
-        return if (toFling < 0 && currentOffset > state.minOffset) {
+        return if (toFling < 0 && currentOffset > state.anchors.minAnchor()) {
             state.settle(velocity = toFling)
             // since we go to the anchor with tween settling, consume all for the best UX
             available
@@ -722,29 +716,6 @@
     private fun Offset.toFloat(): Float = if (orientation == Orientation.Horizontal) x else y
 }
 
-@OptIn(ExperimentalMaterialApi::class)
-private fun BottomSheetScaffoldAnchorChangeCallback(
-    state: BottomSheetState,
-    scope: CoroutineScope
-) = AnchorChangedCallback<BottomSheetValue> { prevTarget, prevAnchors, newAnchors ->
-    val previousTargetOffset = prevAnchors[prevTarget]
-    val newTarget = when (prevTarget) {
-        Collapsed -> Collapsed
-        Expanded -> if (newAnchors.containsKey(Expanded)) Expanded else Collapsed
-    }
-    val newTargetOffset = newAnchors.getValue(newTarget)
-    if (newTargetOffset != previousTargetOffset) {
-        if (state.isAnimationRunning) {
-            // Re-target the animation to the new offset if it changed
-            scope.launch { state.animateTo(newTarget, velocity = state.lastVelocity) }
-        } else {
-            // Snap to the new offset value of the target if no animation was running
-            val didSnapSynchronously = state.trySnapTo(newTarget)
-            if (!didSnapSynchronously) scope.launch { state.snapTo(newTarget) }
-        }
-    }
-}
-
 private val FabSpacing = 16.dp
 private val BottomSheetScaffoldPositionalThreshold = 56.dp
 private val BottomSheetScaffoldVelocityThreshold = 125.dp
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
index 816766c..5a07ee2 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
@@ -30,7 +30,6 @@
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
 import androidx.compose.material.BottomDrawerValue.Closed
 import androidx.compose.material.BottomDrawerValue.Expanded
 import androidx.compose.material.BottomDrawerValue.Open
@@ -68,7 +67,6 @@
 import kotlin.math.max
 import kotlin.math.roundToInt
 import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 
 /**
@@ -391,13 +389,11 @@
 
     internal suspend fun snapTo(target: BottomDrawerValue) = anchoredDraggableState.snapTo(target)
 
-    internal fun trySnapTo(target: BottomDrawerValue) = anchoredDraggableState.trySnapTo(target)
-
     internal fun confirmStateChange(value: BottomDrawerValue): Boolean =
         anchoredDraggableState.confirmValueChange(value)
 
     private val isOpenEnabled: Boolean
-        get() = anchoredDraggableState.hasAnchorForValue(Open)
+        get() = anchoredDraggableState.anchors.hasAnchorFor(Open)
 
     internal val nestedScrollConnection = ConsumeSwipeWithinBottomSheetBoundsNestedScrollConnection(
         anchoredDraggableState
@@ -410,9 +406,6 @@
             " with the BottomDrawer composable?"
     }
 
-    internal val isAnimationRunning: Boolean get() = anchoredDraggableState.isAnimationRunning
-    internal val lastVelocity: Float get() = anchoredDraggableState.lastVelocity
-
     companion object {
         /**
          * The default [Saver] implementation for [BottomDrawerState].
@@ -532,7 +525,10 @@
         val density = LocalDensity.current
         SideEffect {
             drawerState.density = density
-            val anchors = mapOf(DrawerValue.Closed to minValue, DrawerValue.Open to maxValue)
+            val anchors = DraggableAnchors {
+                DrawerValue.Closed at minValue
+                DrawerValue.Open at maxValue
+            }
             drawerState.anchoredDraggableState.updateAnchors(anchors)
         }
 
@@ -700,26 +696,41 @@
                 visible = drawerState.targetValue != Closed
             )
             val navigationMenu = getString(Strings.NavigationMenu)
-            val anchorChangeCallback = remember(drawerState, scope) {
-                BottomDrawerAnchorChangeCallback(drawerState, scope)
-            }
             Surface(
                 drawerConstraints
                     .onSizeChanged { drawerSize ->
                         val drawerHeight = drawerSize.height.toFloat()
-                        val anchors = buildMap {
-                            put(Closed, fullHeight)
+                        val newAnchors = DraggableAnchors {
+                            Closed at fullHeight
                             val peekHeight = fullHeight * BottomDrawerOpenFraction
                             if (drawerHeight > peekHeight || isLandscape) {
-                                put(Open, peekHeight)
+                                Open at peekHeight
                             }
                             if (drawerHeight > 0f) {
-                                put(Expanded, max(0f, fullHeight - drawerHeight))
+                                Expanded at max(0f, fullHeight - drawerHeight)
                             }
                         }
-                        drawerState.anchoredDraggableState.updateAnchors(
-                            anchors, anchorChangeCallback
-                        )
+                        // If we are setting the anchors for the first time and have an anchor for
+                        // the current (initial) value, prefer that
+                        val hasAnchors = drawerState.anchoredDraggableState.anchors.size > 0
+                        val newTarget = if (!hasAnchors &&
+                            newAnchors.hasAnchorFor(drawerState.currentValue)) {
+                            drawerState.currentValue
+                        } else {
+                            when (drawerState.targetValue) {
+                                Closed -> Closed
+                                Open, Expanded -> {
+                                    val hasHalfExpandedState = newAnchors.hasAnchorFor(Open)
+                                    val newTarget = if (hasHalfExpandedState) {
+                                        Open
+                                    } else {
+                                        if (newAnchors.hasAnchorFor(Expanded)) Expanded else Closed
+                                    }
+                                    newTarget
+                                }
+                            }
+                        }
+                        drawerState.anchoredDraggableState.updateAnchors(newAnchors, newTarget)
                     }
                     .offset {
                         IntOffset(
@@ -751,28 +762,6 @@
     }
 }
 
-@OptIn(ExperimentalMaterialApi::class)
-private fun calculateAnchors(
-    fullHeight: Float,
-    drawerHeight: Float,
-    isLandscape: Boolean
-): Map<BottomDrawerValue, Float?> {
-    val peekHeight = fullHeight * BottomDrawerOpenFraction
-    val expandedHeight = max(0f, fullHeight - drawerHeight)
-    return if (drawerHeight < peekHeight || isLandscape) {
-        mapOf(
-            Closed to fullHeight,
-            Expanded to if (drawerHeight == 0f) null else expandedHeight
-        )
-    } else {
-        mapOf(
-            Closed to fullHeight,
-            Open to peekHeight,
-            Expanded to if (drawerHeight == 0f) null else expandedHeight
-        )
-    }
-}
-
 /**
  * Object to hold default values for [ModalDrawer] and [BottomDrawer]
  */
@@ -900,7 +889,7 @@
     override suspend fun onPreFling(available: Velocity): Velocity {
         val toFling = available.toFloat()
         val currentOffset = state.requireOffset()
-        return if (toFling < 0 && currentOffset > state.minOffset) {
+        return if (toFling < 0 && currentOffset > state.anchors.minAnchor()) {
             state.settle(velocity = toFling)
             // since we go to the anchor with tween settling, consume all for the best UX
             available
@@ -925,33 +914,3 @@
     @JvmName("offsetToFloat")
     private fun Offset.toFloat(): Float = if (orientation == Orientation.Horizontal) x else y
 }
-
-@OptIn(ExperimentalMaterialApi::class)
-private fun BottomDrawerAnchorChangeCallback(state: BottomDrawerState, scope: CoroutineScope) =
-    AnchorChangedCallback<BottomDrawerValue> { previousTarget, previousAnchors, newAnchors ->
-        val previousTargetOffset = previousAnchors[previousTarget]
-        val newTarget = when (previousTarget) {
-            Closed -> Closed
-            Open, Expanded -> {
-                val hasHalfExpandedState = newAnchors.containsKey(Open)
-                val newTarget = if (hasHalfExpandedState) {
-                    Open
-                } else {
-                    if (newAnchors.containsKey(Expanded)) Expanded else Closed
-                }
-
-                newTarget
-            }
-        }
-        val newTargetOffset = newAnchors.getValue(newTarget)
-        if (newTargetOffset != previousTargetOffset) {
-            if (state.isAnimationRunning) {
-                // Re-target the animation to the new offset if it changed
-                scope.launch { state.animateTo(newTarget, velocity = state.lastVelocity) }
-            } else {
-                // Snap to the new offset value of the target if no animation was running
-                val didSnapSynchronously = state.trySnapTo(newTarget)
-                if (!didSnapSynchronously) scope.launch { state.snapTo(newTarget) }
-            }
-        }
-    }
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
index e1e32fc..081ca0b 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ModalBottomSheet.kt
@@ -30,7 +30,6 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.widthIn
-import androidx.compose.material.AnchoredDraggableState.AnchorChangedCallback
 import androidx.compose.material.ModalBottomSheetState.Companion.Saver
 import androidx.compose.material.ModalBottomSheetValue.Expanded
 import androidx.compose.material.ModalBottomSheetValue.HalfExpanded
@@ -69,7 +68,6 @@
 import kotlin.math.max
 import kotlin.math.roundToInt
 import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 
 /**
@@ -114,7 +112,7 @@
 fun ModalBottomSheetState(
     initialValue: ModalBottomSheetValue,
     density: Density,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmValueChange: (ModalBottomSheetValue) -> Boolean = { true },
     isSkipHalfExpanded: Boolean = false,
 ) = ModalBottomSheetState(
@@ -160,7 +158,7 @@
 @Suppress("Deprecation")
 fun ModalBottomSheetState(
     initialValue: ModalBottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmValueChange: (ModalBottomSheetValue) -> Boolean = { true },
     isSkipHalfExpanded: Boolean = false
 ) = ModalBottomSheetState(
@@ -194,7 +192,7 @@
     )
 ) constructor(
     initialValue: ModalBottomSheetValue,
-    internal val animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    internal val animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     internal val isSkipHalfExpanded: Boolean = false,
     confirmStateChange: (ModalBottomSheetValue) -> Boolean
 ) {
@@ -240,7 +238,7 @@
         get() = anchoredDraggableState.currentValue != Hidden
 
     internal val hasHalfExpandedState: Boolean
-        get() = anchoredDraggableState.hasAnchorForValue(HalfExpanded)
+        get() = anchoredDraggableState.anchors.hasAnchorFor(HalfExpanded)
 
     @Deprecated(
         message = "This constructor is deprecated. confirmStateChange has been renamed to " +
@@ -301,7 +299,7 @@
      * @throws [CancellationException] if the animation is interrupted
      */
     internal suspend fun expand() {
-        if (!anchoredDraggableState.hasAnchorForValue(Expanded)) {
+        if (!anchoredDraggableState.anchors.hasAnchorFor(Expanded)) {
             return
         }
         animateTo(Expanded)
@@ -323,16 +321,8 @@
     internal suspend fun snapTo(target: ModalBottomSheetValue) =
         anchoredDraggableState.snapTo(target)
 
-    internal fun trySnapTo(target: ModalBottomSheetValue): Boolean {
-        return anchoredDraggableState.trySnapTo(target)
-    }
-
     internal fun requireOffset() = anchoredDraggableState.requireOffset()
 
-    internal val lastVelocity: Float get() = anchoredDraggableState.lastVelocity
-
-    internal val isAnimationRunning: Boolean get() = anchoredDraggableState.isAnimationRunning
-
     internal var density: Density? = null
     private fun requireDensity() = requireNotNull(density) {
         "The density on ModalBottomSheetState ($this) was not set. Did you use " +
@@ -436,7 +426,7 @@
 @Composable
 fun rememberModalBottomSheetState(
     initialValue: ModalBottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmValueChange: (ModalBottomSheetValue) -> Boolean = { true },
     skipHalfExpanded: Boolean = false,
 ): ModalBottomSheetState {
@@ -490,7 +480,7 @@
 @ExperimentalMaterialApi
 fun rememberModalBottomSheetState(
     initialValue: ModalBottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     skipHalfExpanded: Boolean,
     confirmStateChange: (ModalBottomSheetValue) -> Boolean,
 ): ModalBottomSheetState = rememberModalBottomSheetState(
@@ -519,7 +509,7 @@
 @ExperimentalMaterialApi
 fun rememberModalBottomSheetState(
     initialValue: ModalBottomSheetValue,
-    animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec,
+    animationSpec: AnimationSpec<Float> = AnchoredDraggableDefaults.AnimationSpec,
     confirmStateChange: (ModalBottomSheetValue) -> Boolean,
 ): ModalBottomSheetState = rememberModalBottomSheetState(
     initialValue = initialValue,
@@ -581,9 +571,6 @@
     }
     val scope = rememberCoroutineScope()
     val orientation = Orientation.Vertical
-    val anchorChangeCallback = remember(sheetState, scope) {
-        ModalBottomSheetAnchorChangeCallback(sheetState, scope)
-    }
     BoxWithConstraints(modifier) {
         val fullHeight = constraints.maxHeight.toFloat()
         Box(Modifier.fillMaxSize()) {
@@ -629,19 +616,7 @@
                     enabled = sheetGesturesEnabled &&
                         sheetState.anchoredDraggableState.currentValue != Hidden,
                 )
-                .onSizeChanged { sheetSize ->
-                    val anchors = buildMap {
-                        put(Hidden, fullHeight)
-                        val halfHeight = fullHeight / 2f
-                        if (!sheetState.isSkipHalfExpanded && sheetSize.height > halfHeight) {
-                            put(HalfExpanded, halfHeight)
-                        }
-                        if (sheetSize.height != 0) {
-                            put(Expanded, max(0f, fullHeight - sheetSize.height))
-                        }
-                    }
-                    sheetState.anchoredDraggableState.updateAnchors(anchors, anchorChangeCallback)
-                }
+                .modalBottomSheetAnchors(sheetState, fullHeight)
                 .then(
                     if (sheetGesturesEnabled) {
                         Modifier.semantics {
@@ -691,6 +666,46 @@
     }
 }
 
+@OptIn(ExperimentalMaterialApi::class)
+private fun Modifier.modalBottomSheetAnchors(
+    sheetState: ModalBottomSheetState,
+    fullHeight: Float
+) = onSizeChanged { sheetSize ->
+    val newAnchors = DraggableAnchors {
+        Hidden at fullHeight
+        val halfHeight = fullHeight / 2f
+        if (!sheetState.isSkipHalfExpanded && sheetSize.height > halfHeight) {
+            HalfExpanded at halfHeight
+        }
+        if (sheetSize.height != 0) {
+            Expanded at max(0f, fullHeight - sheetSize.height)
+        }
+    }
+    // If we are setting the anchors for the first time and have an anchor for
+    // the current (initial) value, prefer that
+    val isInitialized = sheetState.anchoredDraggableState.anchors.size > 0
+    val previousValue = sheetState.currentValue
+    val newTarget = if (!isInitialized && newAnchors.hasAnchorFor(previousValue)) {
+        previousValue
+    } else {
+        when (sheetState.targetValue) {
+            Hidden -> Hidden
+            HalfExpanded, Expanded -> {
+                val hasHalfExpandedState = newAnchors.hasAnchorFor(HalfExpanded)
+                val newTarget = if (hasHalfExpandedState) {
+                    HalfExpanded
+                } else if (newAnchors.hasAnchorFor(Expanded)) {
+                    Expanded
+                } else {
+                    Hidden
+                }
+                newTarget
+            }
+        }
+    }
+    sheetState.anchoredDraggableState.updateAnchors(newAnchors, newTarget)
+}
+
 @Composable
 private fun Scrim(
     color: Color,
@@ -771,7 +786,7 @@
     override suspend fun onPreFling(available: Velocity): Velocity {
         val toFling = available.toFloat()
         val currentOffset = state.requireOffset()
-        return if (toFling < 0 && currentOffset > state.minOffset) {
+        return if (toFling < 0 && currentOffset > state.anchors.minAnchor()) {
             state.settle(velocity = toFling)
             // since we go to the anchor with tween settling, consume all for the best UX
             available
@@ -797,34 +812,6 @@
     private fun Offset.toFloat(): Float = if (orientation == Orientation.Horizontal) x else y
 }
 
-@OptIn(ExperimentalMaterialApi::class)
-private fun ModalBottomSheetAnchorChangeCallback(
-    state: ModalBottomSheetState,
-    scope: CoroutineScope
-) = AnchorChangedCallback<ModalBottomSheetValue> { prevTarget, prevAnchors, newAnchors ->
-    val previousTargetOffset = prevAnchors[prevTarget]
-    val newTarget = when (prevTarget) {
-        Hidden -> Hidden
-        HalfExpanded, Expanded -> {
-            val hasHalfExpandedState = newAnchors.containsKey(HalfExpanded)
-            val newTarget = if (hasHalfExpandedState) HalfExpanded
-            else if (newAnchors.containsKey(Expanded)) Expanded else Hidden
-            newTarget
-        }
-    }
-    val newTargetOffset = newAnchors.getValue(newTarget)
-    if (newTargetOffset != previousTargetOffset) {
-        if (state.isAnimationRunning) {
-            // Re-target the animation to the new offset if it changed
-            scope.launch { state.animateTo(newTarget, velocity = state.lastVelocity) }
-        } else {
-            // Snap to the new offset value of the target if no animation was running
-            val didSnapSynchronously = state.trySnapTo(newTarget)
-            if (!didSnapSynchronously) scope.launch { state.snapTo(newTarget) }
-        }
-    }
-}
-
 private val ModalBottomSheetPositionalThreshold = 56.dp
 private val ModalBottomSheetVelocityThreshold = 125.dp
 private val MaxModalBottomSheetWidth = 640.dp
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
index 1cda288..a856a28 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@file:Suppress("Deprecation") // b/279939308
 
 package androidx.compose.material
 
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
index f172577..db7fc60 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("Deprecation")
+
 package androidx.compose.material
 
 import androidx.compose.animation.core.Animatable
@@ -76,6 +78,7 @@
  */
 @Stable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 open class SwipeableState<T>(
     initialValue: T,
     internal val animationSpec: AnimationSpec<Float> = AnimationSpec,
@@ -428,6 +431,7 @@
  */
 @Immutable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 class SwipeProgress<T>(
     val from: T,
     val to: T,
@@ -466,6 +470,7 @@
  */
 @Composable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 fun <T : Any> rememberSwipeableState(
     initialValue: T,
     animationSpec: AnimationSpec<Float> = AnimationSpec,
@@ -495,6 +500,7 @@
  */
 @Composable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 internal fun <T : Any> rememberSwipeableStateFor(
     value: T,
     onValueChange: (T) -> Unit,
@@ -561,6 +567,7 @@
  * in order to animate to the next state, even if the positional [thresholds] have not been reached.
  */
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 fun <T> Modifier.swipeable(
     state: SwipeableState<T>,
     anchors: Map<Float, T>,
@@ -626,6 +633,7 @@
  */
 @Stable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 interface ThresholdConfig {
     /**
      * Compute the value of the threshold (in pixels), once the values of the anchors are known.
@@ -640,6 +648,7 @@
  */
 @Immutable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 data class FixedThreshold(private val offset: Dp) : ThresholdConfig {
     override fun Density.computeThreshold(fromValue: Float, toValue: Float): Float {
         return fromValue + offset.toPx() * sign(toValue - fromValue)
@@ -653,6 +662,7 @@
  */
 @Immutable
 @ExperimentalMaterialApi
+@Deprecated(SwipeableDeprecation)
 data class FractionalThreshold(
     /*@FloatRange(from = 0.0, to = 1.0)*/
     private val fraction: Float
@@ -685,6 +695,7 @@
  * Must not be negative.
  */
 @Immutable
+@Deprecated(SwipeableDeprecation)
 class ResistanceConfig(
     /*@FloatRange(from = 0.0, fromInclusive = false)*/
     val basis: Float,
@@ -802,6 +813,7 @@
 /**
  * Contains useful defaults for [swipeable] and [SwipeableState].
  */
+@Deprecated(SwipeableDeprecation)
 object SwipeableDefaults {
     /**
      * The default animation used by [SwipeableState].
@@ -889,3 +901,7 @@
 
         private fun Offset.toFloat(): Float = this.y
     }
+
+private const val SwipeableDeprecation = "Material's Swipeable has been replaced by Foundation's " +
+    "AnchoredDraggable APIs. Please see developer.android.com for an overview of the changes and " +
+    "a migration guide."
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
index 0b2992d..b904b33 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
@@ -41,7 +41,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
@@ -108,19 +107,20 @@
     // a new checked value.
     var forceAnimationCheck by remember { mutableStateOf(false) }
     val switchVelocityThresholdPx = with(LocalDensity.current) { SwitchVelocityThreshold.toPx() }
-    val anchoredDraggableState = remember(switchVelocityThresholdPx) {
+    val anchoredDraggableState = remember(maxBound, switchVelocityThresholdPx) {
         AnchoredDraggableState(
             initialValue = checked,
             animationSpec = AnimationSpec,
+            anchors = DraggableAnchors {
+                false at minBound
+                true at maxBound
+            },
             positionalThreshold = { distance -> distance * SwitchPositionalThreshold },
             velocityThreshold = { switchVelocityThresholdPx }
         )
     }
     val currentOnCheckedChange by rememberUpdatedState(onCheckedChange)
     val currentChecked by rememberUpdatedState(checked)
-    SideEffect {
-        anchoredDraggableState.updateAnchors(mapOf(false to minBound, true to maxBound))
-    }
     LaunchedEffect(anchoredDraggableState) {
         snapshotFlow { anchoredDraggableState.currentValue }
             .collectLatest { newValue ->
diff --git a/compose/material/material/src/test/kotlin/androidx/compose/material/DraggableAnchorsTest.kt b/compose/material/material/src/test/kotlin/androidx/compose/material/DraggableAnchorsTest.kt
new file mode 100644
index 0000000..8c420f3
--- /dev/null
+++ b/compose/material/material/src/test/kotlin/androidx/compose/material/DraggableAnchorsTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalMaterialApi::class)
+
+package androidx.compose.material
+
+import androidx.compose.material.TestValue.A
+import androidx.compose.material.TestValue.B
+import androidx.compose.material.TestValue.C
+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 DraggableAnchorsTest {
+
+    @Test
+    fun draggableAnchors_builder_containsAll() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+            C at 200f
+        }
+        assertThat(anchors.positionOf(A)).isEqualTo(0f)
+        assertThat(anchors.positionOf(B)).isEqualTo(100f)
+        assertThat(anchors.positionOf(C)).isEqualTo(200f)
+    }
+
+    @Test
+    fun draggableAnchors_get_nonexistentAnchor_returnsNaN() {
+        val anchors = DraggableAnchors<TestValue> { }
+        assertThat(anchors.positionOf(A)).isNaN()
+    }
+
+    @Test
+    fun draggableAnchors_findsClosestAnchor() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+            C at 200f
+        }
+        assertThat(anchors.closestAnchor(25f))
+            .isEqualTo(A)
+        assertThat(anchors.closestAnchor(75f))
+            .isEqualTo(B)
+        assertThat(anchors.closestAnchor(175f))
+            .isEqualTo(C)
+    }
+
+    @Test
+    fun draggableAnchors_findsClosestAnchor_directional() {
+        val anchors = DraggableAnchors {
+            A at 0f
+            B at 100f
+        }
+        assertThat(anchors.closestAnchor(1f, searchUpwards = true))
+            .isEqualTo(B)
+        assertThat(anchors.closestAnchor(99f, searchUpwards = false))
+            .isEqualTo(A)
+    }
+
+    @Test
+    fun draggableAnchors_minAnchor() {
+        val anchors = DraggableAnchors {
+            A at -100f
+            B at 100f
+        }
+        assertThat(anchors.minAnchor()).isEqualTo(-100f)
+    }
+
+    @Test
+    fun draggableAnchors_maxAnchor() {
+        val anchors = DraggableAnchors {
+            A at -100f
+            B at 100f
+        }
+        assertThat(anchors.maxAnchor()).isEqualTo(100f)
+    }
+
+    @Test
+    fun draggableAnchors_hasAnchorFor() {
+        val anchors = DraggableAnchors {
+            A at 100f
+        }
+        assertThat(anchors.positionOf(A)).isEqualTo(100f)
+        assertThat(anchors.hasAnchorFor(A)).isTrue()
+    }
+}
+
+private enum class TestValue { A, B, C }
\ No newline at end of file
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt
index 94f7ce2..4e1658b 100644
--- a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffold.kt
@@ -40,7 +40,7 @@
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 private object PaneScaffoldScopeInstance : PaneScaffoldScope {
     override fun Modifier.preferredWidth(width: Dp): Modifier {
-        require(width == Dp.Unspecified || width > 0.dp)
+        require(width == Dp.Unspecified || width > 0.dp) { "invalid width" }
         return this.then(PreferredWidthElement(width))
     }
 }
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/ListSaver.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/ListSaver.kt
index 761fe64..d4f19d52 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/ListSaver.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/ListSaver.kt
@@ -36,7 +36,7 @@
         for (index in list.indices) {
             val item = list[index]
             if (item != null) {
-                require(canBeSaved(item))
+                require(canBeSaved(item)) { "item can't be saved" }
             }
         }
         if (list.isNotEmpty()) ArrayList(list) else null
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/MapSaver.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/MapSaver.kt
index 9bfa09b..9c43afa 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/MapSaver.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/MapSaver.kt
@@ -41,7 +41,7 @@
     },
     restore = { list ->
         val map = mutableMapOf<String, Any?>()
-        check(list.size.rem(2) == 0)
+        check(list.size.rem(2) == 0) { "non-zero remainder" }
         var index = 0
         while (index < list.size) {
             val key = list[index] as String
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
index 68f4cee..4d00665 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/RememberSaveable.kt
@@ -156,7 +156,7 @@
             }
             mutableStateOf(save(state.value), state.policy as SnapshotMutationPolicy<Any?>)
         },
-        restore = @Suppress("UNCHECKED_CAST") {
+        restore = @Suppress("UNCHECKED_CAST", "ExceptionMessage") {
             require(it is SnapshotMutableState<Any?>)
             mutableStateOf(
                 if (it.value != null) restore(it.value!!) else null,
diff --git a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
index f72e681..91c4c1d 100644
--- a/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
+++ b/compose/runtime/runtime-saveable/src/commonMain/kotlin/androidx/compose/runtime/saveable/SaveableStateRegistry.kt
@@ -135,7 +135,7 @@
             if (list.size == 1) {
                 val value = list[0].invoke()
                 if (value != null) {
-                    check(canBeSaved(value))
+                    check(canBeSaved(value)) { "item can't be saved" }
                     map[key] = arrayListOf<Any?>(value)
                 }
             } else {
@@ -147,7 +147,7 @@
                 map[key] = List(list.size) { index ->
                     val value = list[index].invoke()
                     if (value != null) {
-                        check(canBeSaved(value))
+                        check(canBeSaved(value)) { "item can't be saved" }
                     }
                     value
                 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
index 429c007..8cff96a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
@@ -203,7 +203,7 @@
     }
 
     override fun up() {
-        check(stack.isNotEmpty())
+        check(stack.isNotEmpty()) { "empty stack" }
         current = stack.removeAt(stack.size - 1)
     }
 
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
index 41dd2d3..328f19c 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
@@ -3463,6 +3463,7 @@
         return value
     }
 
+    @Suppress("ExceptionMessage")
     fun validateHeap() {
         val size = list.size
         for (index in 0 until size / 2) {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVectorBuilder.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVectorBuilder.kt
index b730a1f..ad6aa069 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVectorBuilder.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableList/PersistentVectorBuilder.kt
@@ -238,8 +238,8 @@
      * Returns the resulting root.
      */
     private fun pushBuffers(root: Array<Any?>?, rootSize: Int, shift: Int, buffersIterator: Iterator<Array<Any?>>): Array<Any?> {
-        check(buffersIterator.hasNext())
-        check(shift >= 0)
+        require(buffersIterator.hasNext()) {"invalid buffersIterator"}
+        require(shift >= 0) {"negative shift"}
 
         if (shift == 0) {
             return buffersIterator.next()
@@ -415,7 +415,7 @@
             nullBuffers: Int,
             nextBuffer: Array<Any?>
     ) {
-        checkNotNull(root)
+        checkNotNull(root) { "root is null" }
 
         val startLeafIndex = index shr LOG_MAX_BUFFER_SIZE
         val startLeaf = shiftLeafBuffers(startLeafIndex, rightShift, buffers, nullBuffers, nextBuffer)
@@ -443,7 +443,7 @@
             nullBuffers: Int,
             nextBuffer: Array<Any?>
     ): Array<Any?> {
-        checkNotNull(root)
+        checkNotNull(root) { "root is null" }
 
         val leafCount = rootSize() shr LOG_MAX_BUFFER_SIZE
 
@@ -476,7 +476,7 @@
             nullBuffers: Int,
             nextBuffer: Array<Any?>
     ) {
-        check(nullBuffers >= 1)
+        require(nullBuffers >= 1) { "requires at least one nullBuffer" }
 
         val firstBuffer = makeMutable(startBuffer)
         buffers[0] = firstBuffer
@@ -742,7 +742,7 @@
      * If the height of the root is bigger than needed to store [size] elements, it's decreased.
      */
     private fun retainFirst(root: Array<Any?>, size: Int): Array<Any?>? {
-        check(size and MAX_BUFFER_SIZE_MINUS_ONE == 0)
+        require(size and MAX_BUFFER_SIZE_MINUS_ONE == 0) { "invalid size" }
 
         if (size == 0) {
             rootShift = 0
@@ -765,7 +765,7 @@
      * Used to prevent memory leaks after reusing nodes.
      */
     private fun nullifyAfter(root: Array<Any?>, index: Int, shift: Int): Array<Any?> {
-        check(shift >= 0)
+        require(shift >= 0) { "shift should be positive" }
 
         if (shift == 0) {
             // the `root` is a leaf buffer.
@@ -974,17 +974,17 @@
     }
 
     private fun leafBufferIterator(index: Int): ListIterator<Array<Any?>> {
-        checkNotNull(root)
+        val root = checkNotNull(root) { "Invalid root" }
 
         val leafCount = rootSize() shr LOG_MAX_BUFFER_SIZE
 
         checkPositionIndex(index, leafCount)
 
         if (rootShift == 0) {
-            return SingleElementListIterator(root!!, index)
+            return SingleElementListIterator(root, index)
         }
 
         val trieHeight = rootShift / LOG_MAX_BUFFER_SIZE
-        return TrieIterator(root!!, index, leafCount, trieHeight)
+        return TrieIterator(root, index, leafCount, trieHeight)
     }
 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
index 8c3336a..b97e1f4 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/external/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt
@@ -635,6 +635,7 @@
             else newNodeMap = newNodeMap or positionMask
             // we can use this later to skip calling equals() again
         }
+        @Suppress("ExceptionMessage")
         check(newNodeMap and newDataMap == 0)
         val mutableNode = when {
             this.ownedBy == mutator.ownership && this.dataMap == newDataMap && this.nodeMap == newNodeMap -> this
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 93559f9..1df3cb2 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -822,7 +822,7 @@
     override fun nestedActivated(snapshot: Snapshot) { snapshots++ }
 
     override fun nestedDeactivated(snapshot: Snapshot) {
-        require(snapshots > 0)
+        require(snapshots > 0) { "no pending nested snapshots" }
         if (--snapshots == 0) {
             if (!applied) {
                 abandon()
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
index 2ae56e8..02367fb 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
@@ -94,7 +94,9 @@
     override fun listIterator(): MutableListIterator<T> = StateListIterator(this, 0)
     override fun listIterator(index: Int): MutableListIterator<T> = StateListIterator(this, index)
     override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
-        require(fromIndex in 0..toIndex && toIndex <= size)
+        require(fromIndex in 0..toIndex && toIndex <= size) {
+            "fromIndex or toIndex are out of bounds"
+        }
         return SubList(this, fromIndex, toIndex)
     }
 
@@ -443,7 +445,9 @@
     }
 
     override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
-        require(fromIndex in 0..toIndex && toIndex <= size)
+        require(fromIndex in 0..toIndex && toIndex <= size) {
+            "fromIndex or toIndex are out of bounds"
+        }
         validateModification()
         return SubList(parentList, fromIndex + offset, toIndex + offset)
     }
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
index f4272bb..d655e27 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
@@ -132,7 +132,7 @@
     }
 
     override fun addRect(rect: Rect) {
-        check(_rectIsValid(rect))
+        check(_rectIsValid(rect)) { "invalid rect" }
         rectF.set(rect.left, rect.top, rect.right, rect.bottom)
         internalPath.addRect(rectF, android.graphics.Path.Direction.CCW)
     }
@@ -147,7 +147,7 @@
     }
 
     override fun addArc(oval: Rect, startAngleDegrees: Float, sweepAngleDegrees: Float) {
-        check(_rectIsValid(oval))
+        check(_rectIsValid(oval)) { "invalid rect" }
         rectF.set(oval.left, oval.top, oval.right, oval.bottom)
         internalPath.addArc(rectF, startAngleDegrees, sweepAngleDegrees)
     }
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/BitmapPainter.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/BitmapPainter.kt
index e2a3738..acbb7ca 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/BitmapPainter.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/BitmapPainter.kt
@@ -120,6 +120,7 @@
     }
 
     private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize {
+        @Suppress("ExceptionMessage")
         require(
             srcOffset.x >= 0 &&
                 srcOffset.y >= 0 &&
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
index ad027c5..8490d41 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
@@ -104,7 +104,9 @@
     private var cachedHasAllParameters = false
     private val cachedNodes: MutableMap<Long, CacheData>
         get() {
-            check(Thread.currentThread() == inspectorThread)
+            check(Thread.currentThread() == inspectorThread) {
+                "cachedNodes should be accessed by the inspector thread"
+            }
             return _cachedNodes
         }
 
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
index e7e58a9..cd729bb 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/AndroidComposeViewWrapper.kt
@@ -99,7 +99,7 @@
 
     init {
         ThreadUtils.assertOnMainThread()
-        check(composeView.isAndroidComposeView())
+        check(composeView.isAndroidComposeView()) { "Invalid view" }
     }
 
     val viewParent =
diff --git a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/UiIssueRegistry.kt b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/UiIssueRegistry.kt
index c5b31bc..5b63347 100644
--- a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/UiIssueRegistry.kt
+++ b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/UiIssueRegistry.kt
@@ -37,9 +37,9 @@
         ModifierDeclarationDetector.ModifierFactoryUnreferencedReceiver,
         ModifierNodeInspectablePropertiesDetector.ModifierNodeInspectableProperties,
         ModifierParameterDetector.ModifierParameter,
+        MultipleAwaitPointerEventScopesDetector.MultipleAwaitPointerEventScopes,
         ReturnFromAwaitPointerEventScopeDetector.ExitAwaitPointerEventScope,
         SuspiciousCompositionLocalModifierReadDetector.SuspiciousCompositionLocalModifierRead,
-        MultipleAwaitPointerEventScopesDetector.MultipleAwaitPointerEventScopes
     )
     override val vendor = Vendor(
         vendorName = "Jetpack Compose",
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
index 425e4f8..7abc0fc 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/MultiModalInjectionScope.kt
@@ -82,7 +82,10 @@
 
     // TODO(b/133217292): Better error: explain which gesture couldn't be performed
     private var _inputDispatcher: InputDispatcher? =
-        createInputDispatcher(testContext, checkNotNull(semanticsNode.root))
+        createInputDispatcher(
+            testContext,
+            checkNotNull(semanticsNode.root) { "null semantics root" }
+        )
     internal val inputDispatcher
         get() = checkNotNull(_inputDispatcher) {
             "Can't send gesture, InjectionScope has already been disposed"
diff --git a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/FrameDeferringContinuationInterceptor.kt b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/FrameDeferringContinuationInterceptor.kt
index d5a055e..2ff66a0 100644
--- a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/FrameDeferringContinuationInterceptor.kt
+++ b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/FrameDeferringContinuationInterceptor.kt
@@ -51,7 +51,7 @@
      */
     fun runWithoutResumingCoroutines(block: () -> Unit) {
         synchronized(lock) {
-            check(!isDeferringContinuations)
+            check(!isDeferringContinuations) { "isDeferringContinuations was not reset" }
             isDeferringContinuations = true
         }
 
diff --git a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.jvm.kt b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.jvm.kt
index 6d588b9..8ec7d39 100644
--- a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.jvm.kt
+++ b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.jvm.kt
@@ -136,7 +136,7 @@
             val frameTime: Long
             @Suppress("PrimitiveInLambda")
             val toRun = synchronized(lock) {
-                check(scheduledFrameDispatch)
+                check(scheduledFrameDispatch) { "frame dispatch not scheduled" }
 
                 frameTime = delayController.currentTime * 1_000_000
                 scheduledFrameDispatch = false
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidFontListTypeface.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidFontListTypeface.android.kt
index 5a79327..1d1caa0 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidFontListTypeface.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidFontListTypeface.android.kt
@@ -70,12 +70,9 @@
             fontMatcher.matchFont(blockingFonts, weight, style).firstOrNull()
         }?.fastFilterNotNull()?.fastDistinctBy { it }
         val targetFonts = matchedFonts ?: blockingFonts
+        check(targetFonts.isNotEmpty()) { "Could not match font" }
 
-        if (targetFonts.isEmpty()) {
-            throw IllegalStateException("Could not match font")
-        }
         val typefaces = mutableMapOf<Font, Typeface>()
-
         targetFonts.fastForEach {
             try {
                 typefaces[it] = AndroidTypefaceCache.getOrCreate(context, it)
@@ -94,10 +91,14 @@
         fontStyle: FontStyle,
         synthesis: FontSynthesis
     ): Typeface {
-        val font = fontMatcher.matchFont(ArrayList(loadedTypefaces.keys), fontWeight, fontStyle)
-            .firstOrNull() ?: throw IllegalStateException("Could not load font")
+        val font = fontMatcher
+            .matchFont(ArrayList(loadedTypefaces.keys), fontWeight, fontStyle)
+            .firstOrNull()
+        checkNotNull(font) { "Could not load font" }
+
         val typeface = loadedTypefaces[font]
-        requireNotNull(typeface)
+        checkNotNull(typeface) { "Could not load typeface" }
+
         return synthesis.synthesizeTypeface(typeface, font, fontWeight, fontStyle) as Typeface
     }
 }
diff --git a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
index 0d93c86..36a7aab 100644
--- a/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
+++ b/compose/ui/ui-tooling/src/jvmMain/kotlin/androidx/compose/ui/tooling/ComposableInvoker.kt
@@ -155,7 +155,7 @@
                 changedParams +
                 defaultParams ==
                 totalParams
-        )
+        ) { "params don't add up to total params" }
 
         val changedStartIndex = composerIndex + 1
         val defaultStartIndex = changedStartIndex + changedParams
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 62f5936..cf1b675 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -2139,7 +2139,7 @@
      * @param size length of the result, should be greater than 0
      */
     private fun <T : CharSequence> trimToSize(text: T?, @IntRange(from = 1) size: Int): T? {
-        require(size > 0)
+        require(size > 0) { "size should be greater than 0" }
         var len = size
         if (text.isNullOrEmpty() || text.length <= size) return text
         if (Character.isHighSurrogate(text[size - 1]) && Character.isLowSurrogate(text[size])) {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
index de8859fe7..2e1dc21 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidViewsHandler.android.kt
@@ -21,6 +21,8 @@
 import android.graphics.Rect
 import android.view.MotionEvent
 import android.view.View
+import android.view.View.MeasureSpec.EXACTLY
+import android.view.View.MeasureSpec.getMode
 import android.view.ViewGroup
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.viewinterop.AndroidViewHolder
@@ -42,8 +44,8 @@
     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
         // Layout will be handled by component nodes. However, we act like proper measurement
         // here in case ViewRootImpl did forceLayout().
-        require(MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY)
-        require(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY)
+        require(getMode(widthMeasureSpec) == EXACTLY) { "widthMeasureSpec should be EXACTLY" }
+        require(getMode(heightMeasureSpec) == EXACTLY) { "heightMeasureSpec should be EXACTLY" }
         setMeasuredDimension(
             MeasureSpec.getSize(widthMeasureSpec),
             MeasureSpec.getSize(heightMeasureSpec)
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/actionmodecallback/TextActionModeCallback.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/actionmodecallback/TextActionModeCallback.android.kt
index 31ee954..97fbb47 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/actionmodecallback/TextActionModeCallback.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/actionmodecallback/TextActionModeCallback.android.kt
@@ -31,8 +31,8 @@
     var onSelectAllRequested: (() -> Unit)? = null
 ) {
     fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
-        requireNotNull(menu)
-        requireNotNull(mode)
+        requireNotNull(menu) { "onCreateActionMode requires a non-null menu" }
+        requireNotNull(mode) { "onCreateActionMode requires a non-null mode" }
 
         onCopyRequested?.let {
             addMenuItem(menu, MenuItemOption.Copy)
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
index 86c5c68..efabfe9 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
@@ -304,7 +304,7 @@
     set(compositeKeyHash, SetCompositeKeyHash)
 }
 
-@Suppress("UNCHECKED_CAST")
+@Suppress("UNCHECKED_CAST", "ExceptionMessage")
 private fun <T : View> LayoutNode.requireViewFactoryHolder(): ViewFactoryHolder<T> {
     @OptIn(InternalComposeUiApi::class)
     return checkNotNull(interopViewFactoryHolder) as ViewFactoryHolder<T>
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Modifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Modifier.kt
index 1868f44..f81c807 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Modifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Modifier.kt
@@ -258,15 +258,15 @@
         internal inline fun isKind(kind: NodeKind<*>) = kindSet and kind.mask != 0
 
         internal open fun attach() {
-            check(!isAttached)
-            check(coordinator != null)
+            check(!isAttached) { "node attached multiple times" }
+            check(coordinator != null) { "attach invoked on a node without a coordinator" }
             isAttached = true
             onAttach()
         }
 
         internal open fun detach() {
-            check(isAttached)
-            check(coordinator != null)
+            check(isAttached) { "node detached multiple times" }
+            check(coordinator != null) { "detach invoked on a node without a coordinator" }
             onDetach()
             isAttached = false
 
@@ -277,7 +277,7 @@
         }
 
         internal open fun reset() {
-            check(isAttached)
+            check(isAttached) { "reset() called on an unattached node" }
             onReset()
         }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
index a791a39..e653e80 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTransactions.kt
@@ -201,7 +201,7 @@
         // If this node is [ActiveParent] ie, one of the parent's descendants is [Active],
         // remove focus from the currently focused child and grant it to the requesting child.
         ActiveParent -> {
-            checkNotNull(activeChild)
+            requireActiveChild()
             (clearChildFocus() && childNode.grantFocus()).also { success ->
                 if (success) childNode.refreshFocusEventNodes()
             }
@@ -225,7 +225,7 @@
                         // Verify that focus state was granted to the child.
                         // If this child didn't take focus then we can end up in a situation where
                         // a deactivated parent is focused.
-                        check(this.focusState == ActiveParent)
+                        check(this.focusState == ActiveParent) { "Deactivated node is focused" }
                     }
                 }
 
@@ -242,6 +242,10 @@
     return coordinator?.layoutNode?.owner?.requestFocus() ?: error("Owner not initialized.")
 }
 
+private fun FocusTargetNode.requireActiveChild(): FocusTargetNode {
+    return requireNotNull(activeChild) { "ActiveParent with no focused child" }
+}
+
 internal enum class CustomDestinationResult { None, Cancelled, Redirected, RedirectCancelled }
 
 internal fun FocusTargetNode.performCustomRequestFocus(
@@ -250,7 +254,7 @@
     when (focusState) {
         Active, Captured -> return None
         ActiveParent ->
-            return checkNotNull(activeChild).performCustomClearFocus(focusDirection)
+            return requireActiveChild().performCustomClearFocus(focusDirection)
         Inactive -> {
             val focusParent = nearestAncestor(FocusTarget) ?: return None
             return when (focusParent.focusState) {
@@ -271,7 +275,7 @@
     Active, Inactive -> None
     Captured -> Cancelled
     ActiveParent ->
-        checkNotNull(activeChild).performCustomClearFocus(focusDirection).takeUnless { it == None }
+        requireActiveChild().performCustomClearFocus(focusDirection).takeUnless { it == None }
             ?: performCustomExit(focusDirection)
 }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
index 4855f77..ca78216 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/OneDimensionalFocusSearch.kt
@@ -27,6 +27,7 @@
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.node.Nodes
 import androidx.compose.ui.node.nearestAncestor
+import androidx.compose.ui.node.requireLayoutNode
 import androidx.compose.ui.node.visitChildren
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.contract
@@ -222,8 +223,8 @@
         focusTarget1: FocusTargetNode?,
         focusTarget2: FocusTargetNode?
     ): Int {
-        requireNotNull(focusTarget1)
-        requireNotNull(focusTarget2)
+        requireNotNull(focusTarget1) { "compare requires non-null focus targets" }
+        requireNotNull(focusTarget2) { "compare requires non-null focus targets" }
 
         // Ignore focus modifiers that won't be considered during focus search.
         if (!focusTarget1.isEligibleForFocusSearch || !focusTarget2.isEligibleForFocusSearch) {
@@ -232,8 +233,8 @@
             return 0
         }
 
-        val layoutNode1 = checkNotNull(focusTarget1.coordinator?.layoutNode)
-        val layoutNode2 = checkNotNull(focusTarget2.coordinator?.layoutNode)
+        val layoutNode1 = focusTarget1.requireLayoutNode()
+        val layoutNode2 = focusTarget2.requireLayoutNode()
 
         // Use natural order for focus modifiers within the same layout node.
         if (layoutNode1 == layoutNode2) return 0
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
index 957db41..c8be093 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusSearch.kt
@@ -380,6 +380,6 @@
 // Find the active descendant.
 @Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
 private fun FocusTargetNode.activeNode(): FocusTargetNode {
-    check(focusState == ActiveParent)
+    check(focusState == ActiveParent) { "Searching for active node in inactive hierarchy" }
     return findActiveFocusNode() ?: error(NoActiveChild)
 }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputTestUtil.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputTestUtil.kt
index a4706cd..967b58a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputTestUtil.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/PointerInputTestUtil.kt
@@ -139,8 +139,8 @@
     pointerEventPasses: List<PointerEventPass>,
     size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
 ) {
-    require(pointerEvent.changes.isNotEmpty())
-    require(pointerEventPasses.isNotEmpty())
+    require(pointerEvent.changes.isNotEmpty()) { "invokeOverPasses called with no changes" }
+    require(pointerEventPasses.isNotEmpty()) { "invokeOverPasses called with no passes" }
     pointerEventPasses.fastForEach {
         this.invoke(pointerEvent, it, size)
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntermediateLayoutModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntermediateLayoutModifierNode.kt
index e0ad52d..2482c76 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntermediateLayoutModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/IntermediateLayoutModifierNode.kt
@@ -24,6 +24,7 @@
 import androidx.compose.ui.node.LayoutModifierNode
 import androidx.compose.ui.node.NodeMeasuringIntrinsics
 import androidx.compose.ui.node.Nodes
+import androidx.compose.ui.node.requireLayoutNode
 import androidx.compose.ui.node.visitAncestors
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntOffset
@@ -83,12 +84,10 @@
     private var intermediateMeasurable: IntermediateMeasurablePlaceable? = null
 
     override fun onAttach() {
-        val layoutNode = coordinator!!.layoutNode
+        val coordinates = coordinator?.lookaheadDelegate?.lookaheadLayoutCoordinates
+        checkNotNull(coordinates) { "could not fetch lookahead coordinates" }
 
-        val coordinates = coordinator!!.lookaheadDelegate?.lookaheadLayoutCoordinates
-        require(coordinates != null)
-
-        val closestLookaheadRoot = layoutNode.lookaheadRoot
+        val closestLookaheadRoot = requireLayoutNode().lookaheadRoot
         closestLookaheadScope = if (closestLookaheadRoot?.isVirtualLookaheadRoot == true) {
             // The closest explicit scope in the tree will be the closest scope, as all
             // descendant intermediateLayoutModifiers will be using that as their LookaheadScope
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
index f5146b8..263068d 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
@@ -414,6 +414,7 @@
         val node = slotIdToNode.getOrPut(slotId) {
             val precomposed = precomposeMap.remove(slotId)
             if (precomposed != null) {
+                @Suppress("ExceptionMessage")
                 check(precomposedCount > 0)
                 precomposedCount--
                 precomposed
@@ -681,10 +682,11 @@
                 makeSureStateIsConsistent()
                 val node = precomposeMap.remove(slotId)
                 if (node != null) {
-                    check(precomposedCount > 0)
+                    check(precomposedCount > 0) { "No pre-composed items to dispose" }
                     val itemIndex = root.foldedChildren.indexOf(node)
-                    // make sure this item is in the precomposed items range
-                    check(itemIndex >= root.foldedChildren.size - precomposedCount)
+                    check(itemIndex >= root.foldedChildren.size - precomposedCount) {
+                        "Item is not in pre-composed item range"
+                    }
                     // move this item into the reusable section
                     reusableCount++
                     precomposedCount--
@@ -706,7 +708,7 @@
                             "Index ($index) is out of bound of [0, $size)"
                         )
                     }
-                    require(!node.isPlaced)
+                    require(!node.isPlaced) { "Pre-measure called on node that is not placed" }
                     root.ignoreRemeasureRequests {
                         node.requireOwner().measureAndLayout(node.children[index], constraints)
                     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalModifierNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalModifierNode.kt
index e91a419..dd3b4c3 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalModifierNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/modifier/ModifierLocalModifierNode.kt
@@ -44,13 +44,14 @@
     }
 
     override operator fun <T> set(key: ModifierLocal<T>, value: T) {
+        @Suppress("ExceptionMessage")
         check(key === this.key)
         this.value = value
     }
 
+    @Suppress("UNCHECKED_CAST", "ExceptionMessage")
     override operator fun <T> get(key: ModifierLocal<T>): T? {
         check(key === this.key)
-        @Suppress("UNCHECKED_CAST")
         return value as? T?
     }
 
@@ -64,9 +65,9 @@
         error("Set is not allowed on a backwards compat provider")
     }
 
+    @Suppress("UNCHECKED_CAST", "ExceptionMessage")
     override operator fun <T> get(key: ModifierLocal<T>): T? {
         check(key === element.key)
-        @Suppress("UNCHECKED_CAST")
         return element.value as T
     }
 
@@ -158,7 +159,7 @@
      */
     override val <T> ModifierLocal<T>.current: T
         get() {
-            require(node.isAttached)
+            require(node.isAttached) { "ModifierLocal accessed from an unattached node" }
             val key = this
             visitAncestors(Nodes.Locals) {
                 if (it.providedValues.contains(key)) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/BackwardsCompatNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/BackwardsCompatNode.kt
index 533ae5f..07b1b3c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/BackwardsCompatNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/BackwardsCompatNode.kt
@@ -111,7 +111,7 @@
     }
 
     private fun unInitializeModifier() {
-        check(isAttached)
+        check(isAttached) { "unInitializeModifier called on unattached node" }
         val element = element
         if (isKind(Nodes.Locals)) {
             if (element is ModifierLocalProvider<*>) {
@@ -132,7 +132,7 @@
     }
 
     private fun initializeModifier(duringAttach: Boolean) {
-        check(isAttached)
+        check(isAttached) { "initializeModifier called on unattached node" }
         val element = element
         if (isKind(Nodes.Locals)) {
             if (element is ModifierLocalProvider<*>) {
@@ -415,13 +415,15 @@
 
     override fun onFocusEvent(focusState: FocusState) {
         val focusEventModifier = element
-        check(focusEventModifier is FocusEventModifier)
+        check(focusEventModifier is FocusEventModifier) { "onFocusEvent called on wrong node" }
         focusEventModifier.onFocusEvent(focusState)
     }
 
     override fun applyFocusProperties(focusProperties: FocusProperties) {
         val focusOrderModifier = element
-        check(focusOrderModifier is FocusOrderModifier)
+        check(focusOrderModifier is FocusOrderModifier) {
+            "applyFocusProperties called on wrong node"
+        }
         focusProperties.apply(FocusOrderModifierToProperties(focusOrderModifier))
     }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatableNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatableNode.kt
index 4c6b373..ece4784 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatableNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatableNode.kt
@@ -311,7 +311,9 @@
         "Cannot obtain node coordinator. Is the Modifier.Node attached?"
     }.layoutNode
 
-internal fun DelegatableNode.requireOwner(): Owner = checkNotNull(requireLayoutNode().owner)
+internal fun DelegatableNode.requireOwner(): Owner = checkNotNull(requireLayoutNode().owner) {
+    "This node does not have an owner."
+}
 
 /**
  * Returns the current [Density] of the LayoutNode that this [DelegatableNode] is attached to.
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet.kt
index f7379ba..6ee9680 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet.kt
@@ -49,34 +49,30 @@
     fun contains(node: LayoutNode): Boolean {
         val contains = set.contains(node)
         if (extraAssertions) {
-            check(contains == mapOfOriginalDepth.containsKey(node))
+            check(contains == mapOfOriginalDepth.containsKey(node)) { "inconsistency in TreeSet" }
         }
         return contains
     }
 
     fun add(node: LayoutNode) {
-        check(node.isAttached)
+        check(node.isAttached) { "DepthSortedSet.add called on an unattached node" }
         if (extraAssertions) {
             val usedDepth = mapOfOriginalDepth[node]
             if (usedDepth == null) {
                 mapOfOriginalDepth[node] = node.depth
             } else {
-                check(usedDepth == node.depth)
+                check(usedDepth == node.depth) { "invalid node depth" }
             }
         }
         set.add(node)
     }
 
     fun remove(node: LayoutNode): Boolean {
-        check(node.isAttached)
+        check(node.isAttached) { "DepthSortedSet.remove called on an unattached node" }
         val contains = set.remove(node)
         if (extraAssertions) {
             val usedDepth = mapOfOriginalDepth.remove(node)
-            if (contains) {
-                check(usedDepth == node.depth)
-            } else {
-                check(usedDepth == null)
-            }
+            check(usedDepth == if (contains) node.depth else null) { "invalid node depth" }
         }
         return contains
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 13b3d42..0ce26d26 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -802,7 +802,7 @@
             }
             val layerCoordinator = _innerLayerCoordinator
             if (layerCoordinator != null) {
-                requireNotNull(layerCoordinator.layer)
+                checkNotNull(layerCoordinator.layer) { "layer was not set" }
             }
             return layerCoordinator
         }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
index 9e079fe..d58eef5 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
@@ -699,7 +699,7 @@
         fun replace() {
             try {
                 relayoutWithoutParentInProgress = true
-                check(placedOnce)
+                check(placedOnce) { "replace called on unplaced item" }
                 placeOuterCoordinator(lastPosition, lastZIndex, lastLayerBlock)
             } finally {
                 relayoutWithoutParentInProgress = false
@@ -899,8 +899,8 @@
          */
         fun measureBasedOnLookahead() {
             val lookaheadDelegate = lookaheadPassDelegate
-            val parent = layoutNode.parent!!
-            requireNotNull(lookaheadDelegate)
+            val parent = checkNotNull(layoutNode.parent) { "layoutNode parent is not set" }
+            checkNotNull(lookaheadDelegate) { "invalid lookaheadDelegate" }
             if (lookaheadDelegate.measuredByParent == LayoutNode.UsageByParent.InMeasureBlock &&
                 parent.layoutState == LayoutState.Measuring
             ) {
@@ -918,7 +918,9 @@
          * layerBlock as lookahead.
          */
         fun placeBasedOnLookahead() {
-            val lookaheadDelegate = requireNotNull(lookaheadPassDelegate)
+            val lookaheadDelegate = checkNotNull(lookaheadPassDelegate) {
+                "invalid lookaheadDelegate"
+            }
             placeAt(
                 lookaheadDelegate.lastPosition,
                 lookaheadDelegate.lastZIndex,
@@ -1461,7 +1463,7 @@
         fun replace() {
             try {
                 relayoutWithoutParentInProgress = true
-                check(placedOnce)
+                check(placedOnce) { "replace() called on item that was not placed" }
                 placeAt(lastPosition, 0f, null)
             } finally {
                 relayoutWithoutParentInProgress = false
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
index e743af7..5954d8d 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
@@ -95,7 +95,7 @@
      */
     fun updateRootConstraints(constraints: Constraints) {
         if (rootConstraints != constraints) {
-            require(!duringMeasureLayout)
+            require(!duringMeasureLayout) { "updateRootConstraints called while measuring" }
             rootConstraints = constraints
             if (root.lookaheadRoot != null) {
                 root.markLookaheadMeasurePending()
@@ -380,7 +380,7 @@
     }
 
     fun measureAndLayout(layoutNode: LayoutNode, constraints: Constraints) {
-        require(layoutNode != root)
+        require(layoutNode != root) { "measureAndLayout called on root" }
         performMeasureAndLayout {
             relayoutNodes.remove(layoutNode)
             // we don't check for the layoutState as even if the node doesn't need remeasure
@@ -401,9 +401,9 @@
     }
 
     private inline fun performMeasureAndLayout(block: () -> Unit) {
-        require(root.isAttached)
-        require(root.isPlaced)
-        require(!duringMeasureLayout)
+        require(root.isAttached) { "performMeasureAndLayout called with unattached root" }
+        require(root.isPlaced) { "performMeasureAndLayout called with unplaced root" }
+        require(!duringMeasureLayout) { "performMeasureAndLayout called during measure layout" }
         // we don't need to measure any children unless we have the correct root constraints
         if (rootConstraints != null) {
             duringMeasureLayout = true
@@ -516,7 +516,9 @@
         }
 
         // assert that it is executed during the `measureAndLayout` pass.
-        check(duringMeasureLayout)
+        check(duringMeasureLayout) {
+            "forceMeasureTheSubtree should be executed during the measureAndLayout pass"
+        }
 
         val pending: (LayoutNode) -> Boolean = {
             if (affectsLookahead) {
@@ -526,7 +528,7 @@
             }
         }
         // if this node is not yet measured this invocation shouldn't be needed.
-        require(!pending(layoutNode))
+        require(!pending(layoutNode)) { "node not yet measured" }
 
         layoutNode.forEachChild { child ->
             if (pending(child) && relayoutNodes.remove(child, affectsLookahead)) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureScopeWithLayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureScopeWithLayoutNode.kt
index a8abf18..58eb96e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureScopeWithLayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureScopeWithLayoutNode.kt
@@ -40,7 +40,7 @@
         LayoutState.Measuring, LayoutState.LayingOut -> false
         LayoutState.Idle -> {
             // idle means intrinsics are being asked, we need to check the parent
-            requireNotNull(parent).isInLookaheadPass()
+            requireNotNull(parent) { "no parent for idle node" }.isInLookaheadPass()
         }
     }
 }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MyersDiff.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MyersDiff.kt
index d7172cf..2721353 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MyersDiff.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MyersDiff.kt
@@ -464,7 +464,7 @@
         // sort. If it is greater than 3, we pass in the index of the "start" element of the last
         // diagonal
         val i = lastIndex
-        check(i % 3 == 0)
+        check(i % 3 == 0) { "Array size not a multiple of 3" }
         if (i > 3) {
             quickSort(0, i - 3, 3)
         }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
index 23c09c2..c48e1d8 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeChain.kt
@@ -50,7 +50,7 @@
     }
 
     private fun padChain() {
-        check(head !== SentinelHead)
+        check(head !== SentinelHead) { "padChain encountered an invalid head" }
         val currentHead = head
         currentHead.parent = SentinelHead
         SentinelHead.child = currentHead
@@ -58,11 +58,11 @@
     }
 
     private fun trimChain() {
-        check(head === SentinelHead)
+        check(head === SentinelHead) { "trimChain encountered an invalid head" }
         head = SentinelHead.child ?: tail
         head.parent = null
         SentinelHead.child = null
-        check(head !== SentinelHead)
+        check(head !== SentinelHead) { "trimChain did not update the head" }
     }
 
     /**
@@ -146,7 +146,7 @@
             }
 
             if (i > 0) {
-                check(node != null)
+                checkNotNull(node) { "structuralUpdate requires a non-null tail" }
                 attachNeeded = true
                 coordinatorSyncNeeded = true
                 // there must have been a structural change
@@ -294,7 +294,9 @@
         val infoList = MutableVector<ModifierInfo>(current.size)
         var i = 0
         headToTailExclusive { node ->
-            val coordinator = requireNotNull(node.coordinator)
+            val coordinator = requireNotNull(node.coordinator) {
+                "getModifierInfo called on node with no coordinator"
+            }
             // placeWithLayer puts the layer on the _next_ coordinator
             //
             // - If the last node does placeWithLayer, the layer is on the innerCoordinator
@@ -376,7 +378,7 @@
         override fun insert(atIndex: Int, newIndex: Int) {
             val child = node
             node = createAndInsertNodeAsParent(after[newIndex], child)
-            check(!node.isAttached)
+            check(!node.isAttached) { "createAndInsertNodeAsParent called on an attached node" }
             node.insertedNodeAwaitingAttachForInvalidation = true
             logger?.nodeInserted(atIndex, newIndex, after[newIndex], child, node)
             aggregateChildKindSet = aggregateChildKindSet or node.kindSet
@@ -545,7 +547,7 @@
             }
             else -> BackwardsCompatNode(element)
         }
-        check(!node.isAttached)
+        check(!node.isAttached) { "createAndInsertNodeAsParent called on an attached node" }
         node.insertedNodeAwaitingAttachForInvalidation = true
         return insertParent(node, child)
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
index 0e9b845..5593ddd 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeCoordinator.kt
@@ -435,7 +435,9 @@
     private fun updateLayerParameters(invokeOnLayoutChange: Boolean = true) {
         val layer = layer
         if (layer != null) {
-            val layerBlock = requireNotNull(layerBlock)
+            val layerBlock = checkNotNull(layerBlock) {
+                "updateLayerParameters requires a non-null layerBlock"
+            }
             graphicsLayerScope.reset()
             graphicsLayerScope.graphicsDensity = layoutNode.density
             graphicsLayerScope.size = size.toSize()
@@ -472,7 +474,7 @@
                 layoutNode.owner?.onLayoutChange(layoutNode)
             }
         } else {
-            require(layerBlock == null)
+            check(layerBlock == null) { "non-null layer with a null layerBlock" }
         }
     }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeKind.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeKind.kt
index 9aade67..0c04a09 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeKind.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/NodeKind.kt
@@ -214,17 +214,17 @@
 private const val Removed = 2
 
 internal fun autoInvalidateRemovedNode(node: Modifier.Node) {
-    check(node.isAttached)
+    check(node.isAttached) { "autoInvalidateRemovedNode called on unattached node" }
     autoInvalidateNodeIncludingDelegates(node, 0.inv(), Removed)
 }
 
 internal fun autoInvalidateInsertedNode(node: Modifier.Node) {
-    check(node.isAttached)
+    check(node.isAttached) { "autoInvalidateInsertedNode called on unattached node" }
     autoInvalidateNodeIncludingDelegates(node, 0.inv(), Inserted)
 }
 
 internal fun autoInvalidateUpdatedNode(node: Modifier.Node) {
-    check(node.isAttached)
+    check(node.isAttached) { "autoInvalidateUpdatedNode called on unattached node" }
     autoInvalidateNodeIncludingDelegates(node, 0.inv(), Updated)
 }
 
@@ -317,7 +317,7 @@
 private object CanFocusChecker : FocusProperties {
     private var canFocusValue: Boolean? = null
     override var canFocus: Boolean
-        get() = checkNotNull(canFocusValue)
+        get() = checkNotNull(canFocusValue) { "canFocus is read before it is written" }
         set(value) { canFocusValue = value }
     fun isCanFocusSet(): Boolean = canFocusValue != null
     fun reset() { canFocusValue = null }
diff --git a/datastore/datastore-core/api/current.txt b/datastore/datastore-core/api/current.txt
index 1c52e50..9122777 100644
--- a/datastore/datastore-core/api/current.txt
+++ b/datastore/datastore-core/api/current.txt
@@ -37,6 +37,11 @@
   @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING, message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface ExperimentalMultiProcessDataStore {
   }
 
+  public final class FileStorage<T> implements androidx.datastore.core.Storage<T> {
+    ctor public FileStorage(androidx.datastore.core.Serializer<T> serializer, optional kotlin.jvm.functions.Function1<? super java.io.File,? extends androidx.datastore.core.InterProcessCoordinator> coordinatorProducer, kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+    method public androidx.datastore.core.StorageConnection<T> createConnection();
+  }
+
   public interface InterProcessCoordinator {
     method public kotlinx.coroutines.flow.Flow<kotlin.Unit> getUpdateNotifications();
     method public suspend Object? getVersion(kotlin.coroutines.Continuation<? super java.lang.Integer>);
diff --git a/datastore/datastore-core/api/restricted_current.txt b/datastore/datastore-core/api/restricted_current.txt
index 1c52e50..9122777 100644
--- a/datastore/datastore-core/api/restricted_current.txt
+++ b/datastore/datastore-core/api/restricted_current.txt
@@ -37,6 +37,11 @@
   @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING, message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface ExperimentalMultiProcessDataStore {
   }
 
+  public final class FileStorage<T> implements androidx.datastore.core.Storage<T> {
+    ctor public FileStorage(androidx.datastore.core.Serializer<T> serializer, optional kotlin.jvm.functions.Function1<? super java.io.File,? extends androidx.datastore.core.InterProcessCoordinator> coordinatorProducer, kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
+    method public androidx.datastore.core.StorageConnection<T> createConnection();
+  }
+
   public interface InterProcessCoordinator {
     method public kotlinx.coroutines.flow.Flow<kotlin.Unit> getUpdateNotifications();
     method public suspend Object? getVersion(kotlin.coroutines.Continuation<? super java.lang.Integer>);
diff --git a/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt b/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
index ace5688..148c1ed 100644
--- a/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
+++ b/datastore/datastore-core/src/jvmMain/kotlin/androidx/datastore/core/FileStorage.kt
@@ -17,7 +17,6 @@
 package androidx.datastore.core
 
 import androidx.annotation.GuardedBy
-import androidx.annotation.RestrictTo
 import java.io.File
 import java.io.FileInputStream
 import java.io.FileNotFoundException
@@ -28,16 +27,15 @@
 import kotlinx.coroutines.sync.withLock
 
 /**
- * The Java IO File version of the Storage<T> interface. Is able to read and write T to a given
+ * The Java IO File version of the Storage<T> interface. Is able to read and write [T] to a given
  * file location.
  *
- * @param serializer The serializer that can write <T> to and from a byte array.
+ * @param serializer The serializer that can write [T] to and from a byte array.
  * @param coordinatorProducer The producer to provide [InterProcessCoordinator] that coordinates IO
  * operations across processes if needed. By default it provides single process coordinator, which
  * doesn't support cross process use cases.
  * @param produceFile The file producer that returns the file that will be read and written.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class FileStorage<T>(
     private val serializer: Serializer<T>,
     private val coordinatorProducer: (File) -> InterProcessCoordinator = {
@@ -205,4 +203,4 @@
             //  result in reverting to a previous state.
         }
     }
-}
\ No newline at end of file
+}
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 8ca6f01..7f43cd3 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -257,8 +257,8 @@
     docs("androidx.navigation:navigation-ui-ktx:2.7.0-alpha01")
     docs("androidx.paging:paging-common:3.2.0-alpha06")
     docs("androidx.paging:paging-common-ktx:3.2.0-alpha06")
-    docs("androidx.paging:paging-compose:1.0.0-alpha20")
-    samples("androidx.paging:paging-compose-samples:1.0.0-alpha20")
+    docs("androidx.paging:paging-compose:3.2.0-beta01")
+    samples("androidx.paging:paging-compose-samples:3.2.0-beta01")
     docs("androidx.paging:paging-guava:3.2.0-alpha06")
     docs("androidx.paging:paging-runtime:3.2.0-alpha06")
     docs("androidx.paging:paging-runtime-ktx:3.2.0-alpha06")
@@ -372,11 +372,11 @@
     docs("androidx.wear.protolayout:protolayout-expression:1.0.0-alpha10")
     docs("androidx.wear.protolayout:protolayout-material:1.0.0-alpha10")
     docs("androidx.wear.protolayout:protolayout-renderer:1.0.0-alpha10")
-    docs("androidx.wear.tiles:tiles:1.2.0-alpha06")
-    docs("androidx.wear.tiles:tiles-material:1.2.0-alpha06")
-    docs("androidx.wear.tiles:tiles-proto:1.2.0-alpha06")
-    docs("androidx.wear.tiles:tiles-renderer:1.2.0-alpha06")
-    docs("androidx.wear.tiles:tiles-testing:1.2.0-alpha06")
+    docs("androidx.wear.tiles:tiles:1.2.0-alpha07")
+    docs("androidx.wear.tiles:tiles-material:1.2.0-alpha07")
+    docs("androidx.wear.tiles:tiles-proto:1.2.0-alpha07")
+    docs("androidx.wear.tiles:tiles-renderer:1.2.0-alpha07")
+    docs("androidx.wear.tiles:tiles-testing:1.2.0-alpha07")
     docs("androidx.wear.tiles:tiles-tooling:1.2.0-alpha06")
     docs("androidx.wear.watchface:watchface:1.2.0-alpha08")
     docs("androidx.wear.watchface:watchface-client:1.2.0-alpha08")
diff --git a/dynamicanimation/dynamicanimation/api/0.0.0.txt b/dynamicanimation/dynamicanimation/api/0.0.0.txt
deleted file mode 100644
index 1a62176..0000000
--- a/dynamicanimation/dynamicanimation/api/0.0.0.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-package androidx.dynamicanimation.animation {
-
-  public abstract class DynamicAnimation<T extends androidx.dynamicanimation.animation.DynamicAnimation<T>> {
-    method public T addEndListener(androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener);
-    method public T addUpdateListener(androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationUpdateListener);
-    method public void cancel();
-    method public float getMinimumVisibleChange();
-    method public boolean isRunning();
-    method public void removeEndListener(androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener);
-    method public void removeUpdateListener(androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationUpdateListener);
-    method public T setMaxValue(float);
-    method public T setMinValue(float);
-    method public T setMinimumVisibleChange(float);
-    method public T setStartValue(float);
-    method public T setStartVelocity(float);
-    method public void start();
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty ALPHA;
-    field public static final float MIN_VISIBLE_CHANGE_ALPHA = 0.00390625f;
-    field public static final float MIN_VISIBLE_CHANGE_PIXELS = 1.0f;
-    field public static final float MIN_VISIBLE_CHANGE_ROTATION_DEGREES = 0.1f;
-    field public static final float MIN_VISIBLE_CHANGE_SCALE = 0.002f;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty ROTATION;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty ROTATION_X;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty ROTATION_Y;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty SCALE_X;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty SCALE_Y;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty SCROLL_X;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty SCROLL_Y;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty TRANSLATION_X;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty TRANSLATION_Y;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty TRANSLATION_Z;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty X;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty Y;
-    field public static final androidx.dynamicanimation.animation.DynamicAnimation.ViewProperty Z;
-  }
-
-  public static abstract interface DynamicAnimation.OnAnimationEndListener {
-    method public abstract void onAnimationEnd(androidx.dynamicanimation.animation.DynamicAnimation, boolean, float, float);
-  }
-
-  public static abstract interface DynamicAnimation.OnAnimationUpdateListener {
-    method public abstract void onAnimationUpdate(androidx.dynamicanimation.animation.DynamicAnimation, float, float);
-  }
-
-  public static abstract class DynamicAnimation.ViewProperty extends androidx.dynamicanimation.animation.FloatPropertyCompat {
-  }
-
-  public final class FlingAnimation extends androidx.dynamicanimation.animation.DynamicAnimation {
-    ctor public FlingAnimation(androidx.dynamicanimation.animation.FloatValueHolder);
-    ctor public FlingAnimation(K, androidx.dynamicanimation.animation.FloatPropertyCompat<K>);
-    method public float getFriction();
-    method public androidx.dynamicanimation.animation.FlingAnimation setFriction(float);
-    method public androidx.dynamicanimation.animation.FlingAnimation setMaxValue(float);
-    method public androidx.dynamicanimation.animation.FlingAnimation setMinValue(float);
-    method public androidx.dynamicanimation.animation.FlingAnimation setStartVelocity(float);
-  }
-
-  public abstract class FloatPropertyCompat<T> {
-    ctor public FloatPropertyCompat(java.lang.String);
-    method public static <T> androidx.dynamicanimation.animation.FloatPropertyCompat<T> createFloatPropertyCompat(android.util.FloatProperty<T>);
-    method public abstract float getValue(T);
-    method public abstract void setValue(T, float);
-  }
-
-  public final class FloatValueHolder {
-    ctor public FloatValueHolder();
-    ctor public FloatValueHolder(float);
-    method public float getValue();
-    method public void setValue(float);
-  }
-
-  public final class SpringAnimation extends androidx.dynamicanimation.animation.DynamicAnimation {
-    ctor public SpringAnimation(androidx.dynamicanimation.animation.FloatValueHolder);
-    ctor public SpringAnimation(K, androidx.dynamicanimation.animation.FloatPropertyCompat<K>);
-    ctor public SpringAnimation(K, androidx.dynamicanimation.animation.FloatPropertyCompat<K>, float);
-    method public void animateToFinalPosition(float);
-    method public boolean canSkipToEnd();
-    method public androidx.dynamicanimation.animation.SpringForce getSpring();
-    method public androidx.dynamicanimation.animation.SpringAnimation setSpring(androidx.dynamicanimation.animation.SpringForce);
-    method public void skipToEnd();
-  }
-
-  public final class SpringForce {
-    ctor public SpringForce();
-    ctor public SpringForce(float);
-    method public float getDampingRatio();
-    method public float getFinalPosition();
-    method public float getStiffness();
-    method public androidx.dynamicanimation.animation.SpringForce setDampingRatio(float);
-    method public androidx.dynamicanimation.animation.SpringForce setFinalPosition(float);
-    method public androidx.dynamicanimation.animation.SpringForce setStiffness(float);
-    field public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f;
-    field public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f;
-    field public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f;
-    field public static final float DAMPING_RATIO_NO_BOUNCY = 1.0f;
-    field public static final float STIFFNESS_HIGH = 10000.0f;
-    field public static final float STIFFNESS_LOW = 200.0f;
-    field public static final float STIFFNESS_MEDIUM = 1500.0f;
-    field public static final float STIFFNESS_VERY_LOW = 50.0f;
-  }
-
-}
-
diff --git a/emoji/emoji-appcompat/api/0.0.0.txt b/emoji/emoji-appcompat/api/0.0.0.txt
deleted file mode 100644
index 8d3945e..0000000
--- a/emoji/emoji-appcompat/api/0.0.0.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-package androidx.emoji.widget {
-
-  public class EmojiAppCompatButton extends androidx.appcompat.widget.AppCompatButton {
-    ctor public EmojiAppCompatButton(android.content.Context);
-    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiAppCompatButton(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class EmojiAppCompatEditText extends androidx.appcompat.widget.AppCompatEditText {
-    ctor public EmojiAppCompatEditText(android.content.Context);
-    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiAppCompatEditText(android.content.Context, android.util.AttributeSet, int);
-    method public int getMaxEmojiCount();
-    method public void setMaxEmojiCount(int);
-  }
-
-  public class EmojiAppCompatTextView extends androidx.appcompat.widget.AppCompatTextView {
-    ctor public EmojiAppCompatTextView(android.content.Context);
-    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiAppCompatTextView(android.content.Context, android.util.AttributeSet, int);
-  }
-
-}
-
diff --git a/emoji/emoji-bundled/api/0.0.0.txt b/emoji/emoji-bundled/api/0.0.0.txt
deleted file mode 100644
index f216675..0000000
--- a/emoji/emoji-bundled/api/0.0.0.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-package androidx.emoji.bundled {
-
-  public class BundledEmojiCompatConfig extends androidx.emoji.text.EmojiCompat.Config {
-    ctor public BundledEmojiCompatConfig(android.content.Context);
-  }
-
-}
-
diff --git a/emoji/emoji/api/0.0.0.txt b/emoji/emoji/api/0.0.0.txt
deleted file mode 100644
index 785f44ab..0000000
--- a/emoji/emoji/api/0.0.0.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-package androidx.emoji.text {
-
-  public class EmojiCompat {
-    method public static androidx.emoji.text.EmojiCompat get();
-    method public java.lang.String getAssetSignature();
-    method public int getLoadState();
-    method public static boolean handleDeleteSurroundingText(android.view.inputmethod.InputConnection, android.text.Editable, int, int, boolean);
-    method public static boolean handleOnKeyDown(android.text.Editable, int, android.view.KeyEvent);
-    method public boolean hasEmojiGlyph(java.lang.CharSequence);
-    method public boolean hasEmojiGlyph(java.lang.CharSequence, int);
-    method public static androidx.emoji.text.EmojiCompat init(androidx.emoji.text.EmojiCompat.Config);
-    method public java.lang.CharSequence process(java.lang.CharSequence);
-    method public java.lang.CharSequence process(java.lang.CharSequence, int, int);
-    method public java.lang.CharSequence process(java.lang.CharSequence, int, int, int);
-    method public java.lang.CharSequence process(java.lang.CharSequence, int, int, int, int);
-    method public void registerInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
-    method public void unregisterInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
-    field public static final java.lang.String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
-    field public static final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
-    field public static final int LOAD_STATE_FAILED = 2; // 0x2
-    field public static final int LOAD_STATE_LOADING = 0; // 0x0
-    field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
-    field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
-    field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
-    field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
-  }
-
-  public static abstract class EmojiCompat.Config {
-    ctor protected EmojiCompat.Config(androidx.emoji.text.EmojiCompat.MetadataRepoLoader);
-    method protected final androidx.emoji.text.EmojiCompat.MetadataRepoLoader getMetadataRepoLoader();
-    method public androidx.emoji.text.EmojiCompat.Config registerInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
-    method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorColor(int);
-    method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
-    method public androidx.emoji.text.EmojiCompat.Config setReplaceAll(boolean);
-    method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
-    method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer>);
-    method public androidx.emoji.text.EmojiCompat.Config unregisterInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
-  }
-
-  public static abstract class EmojiCompat.InitCallback {
-    ctor public EmojiCompat.InitCallback();
-    method public void onFailed(java.lang.Throwable);
-    method public void onInitialized();
-  }
-
-  public static abstract interface EmojiCompat.MetadataRepoLoader {
-    method public abstract void load(androidx.emoji.text.EmojiCompat.MetadataRepoLoaderCallback);
-  }
-
-  public static abstract class EmojiCompat.MetadataRepoLoaderCallback {
-    ctor public EmojiCompat.MetadataRepoLoaderCallback();
-    method public abstract void onFailed(java.lang.Throwable);
-    method public abstract void onLoaded(androidx.emoji.text.MetadataRepo);
-  }
-
-  public abstract class EmojiSpan extends android.text.style.ReplacementSpan {
-    method public int getSize(android.graphics.Paint, java.lang.CharSequence, int, int, android.graphics.Paint.FontMetricsInt);
-  }
-
-  public class FontRequestEmojiCompatConfig extends androidx.emoji.text.EmojiCompat.Config {
-    ctor public FontRequestEmojiCompatConfig(android.content.Context, androidx.core.provider.FontRequest);
-    method public androidx.emoji.text.FontRequestEmojiCompatConfig setHandler(android.os.Handler);
-    method public androidx.emoji.text.FontRequestEmojiCompatConfig setRetryPolicy(androidx.emoji.text.FontRequestEmojiCompatConfig.RetryPolicy);
-  }
-
-  public static class FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy extends androidx.emoji.text.FontRequestEmojiCompatConfig.RetryPolicy {
-    ctor public FontRequestEmojiCompatConfig.ExponentialBackoffRetryPolicy(long);
-    method public long getRetryDelay();
-  }
-
-  public static abstract class FontRequestEmojiCompatConfig.RetryPolicy {
-    ctor public FontRequestEmojiCompatConfig.RetryPolicy();
-    method public abstract long getRetryDelay();
-  }
-
-  public final class MetadataRepo {
-    method public static androidx.emoji.text.MetadataRepo create(android.graphics.Typeface, java.io.InputStream) throws java.io.IOException;
-    method public static androidx.emoji.text.MetadataRepo create(android.graphics.Typeface, java.nio.ByteBuffer) throws java.io.IOException;
-    method public static androidx.emoji.text.MetadataRepo create(android.content.res.AssetManager, java.lang.String) throws java.io.IOException;
-  }
-
-}
-
-package androidx.emoji.widget {
-
-  public class EmojiButton extends android.widget.Button {
-    ctor public EmojiButton(android.content.Context);
-    ctor public EmojiButton(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int);
-    ctor public EmojiButton(android.content.Context, android.util.AttributeSet, int, int);
-  }
-
-  public class EmojiEditText extends android.widget.EditText {
-    ctor public EmojiEditText(android.content.Context);
-    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int);
-    ctor public EmojiEditText(android.content.Context, android.util.AttributeSet, int, int);
-    method public int getMaxEmojiCount();
-    method public void setMaxEmojiCount(int);
-  }
-
-  public final class EmojiEditTextHelper {
-    ctor public EmojiEditTextHelper(android.widget.EditText);
-    method public android.text.method.KeyListener getKeyListener(android.text.method.KeyListener);
-    method public int getMaxEmojiCount();
-    method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
-    method public void setMaxEmojiCount(int);
-  }
-
-  public class EmojiExtractTextLayout extends android.widget.LinearLayout {
-    ctor public EmojiExtractTextLayout(android.content.Context);
-    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet, int);
-    ctor public EmojiExtractTextLayout(android.content.Context, android.util.AttributeSet, int, int);
-    method public int getEmojiReplaceStrategy();
-    method public void onUpdateExtractingViews(android.inputmethodservice.InputMethodService, android.view.inputmethod.EditorInfo);
-    method public void setEmojiReplaceStrategy(int);
-  }
-
-  public class EmojiTextView extends android.widget.TextView {
-    ctor public EmojiTextView(android.content.Context);
-    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet);
-    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int);
-    ctor public EmojiTextView(android.content.Context, android.util.AttributeSet, int, int);
-  }
-
-  public final class EmojiTextViewHelper {
-    ctor public EmojiTextViewHelper(android.widget.TextView);
-    method public android.text.InputFilter[] getFilters(android.text.InputFilter[]);
-    method public void setAllCaps(boolean);
-    method public void updateTransformationMethod();
-    method public android.text.method.TransformationMethod wrapTransformationMethod(android.text.method.TransformationMethod);
-  }
-
-}
-
diff --git a/fragment/fragment/api/0.0.0.txt b/fragment/fragment/api/0.0.0.txt
deleted file mode 100644
index 2c587ff..0000000
--- a/fragment/fragment/api/0.0.0.txt
+++ /dev/null
@@ -1,386 +0,0 @@
-package androidx.fragment.app {
-
-  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
-    ctor public DialogFragment();
-    method public void dismiss();
-    method public void dismissAllowingStateLoss();
-    method public android.app.Dialog getDialog();
-    method public boolean getShowsDialog();
-    method public int getTheme();
-    method public boolean isCancelable();
-    method public void onCancel(android.content.DialogInterface);
-    method public android.app.Dialog onCreateDialog(android.os.Bundle);
-    method public void onDismiss(android.content.DialogInterface);
-    method public void setCancelable(boolean);
-    method public void setShowsDialog(boolean);
-    method public void setStyle(int, int);
-    method public void show(androidx.fragment.app.FragmentManager, java.lang.String);
-    method public int show(androidx.fragment.app.FragmentTransaction, java.lang.String);
-    method public void showNow(androidx.fragment.app.FragmentManager, java.lang.String);
-    field public static final int STYLE_NORMAL = 0; // 0x0
-    field public static final int STYLE_NO_FRAME = 2; // 0x2
-    field public static final int STYLE_NO_INPUT = 3; // 0x3
-    field public static final int STYLE_NO_TITLE = 1; // 0x1
-  }
-
-  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.LifecycleOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
-    ctor public Fragment();
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public final boolean equals(java.lang.Object);
-    method public final androidx.fragment.app.FragmentActivity getActivity();
-    method public boolean getAllowEnterTransitionOverlap();
-    method public boolean getAllowReturnTransitionOverlap();
-    method public final android.os.Bundle getArguments();
-    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
-    method public android.content.Context getContext();
-    method public java.lang.Object getEnterTransition();
-    method public java.lang.Object getExitTransition();
-    method public final androidx.fragment.app.FragmentManager getFragmentManager();
-    method public final java.lang.Object getHost();
-    method public final int getId();
-    method public final android.view.LayoutInflater getLayoutInflater();
-    method public androidx.lifecycle.Lifecycle getLifecycle();
-    method public androidx.loader.app.LoaderManager getLoaderManager();
-    method public final androidx.fragment.app.Fragment getParentFragment();
-    method public java.lang.Object getReenterTransition();
-    method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
-    method public java.lang.Object getReturnTransition();
-    method public java.lang.Object getSharedElementEnterTransition();
-    method public java.lang.Object getSharedElementReturnTransition();
-    method public final java.lang.String getString(int);
-    method public final java.lang.String getString(int, java.lang.Object...);
-    method public final java.lang.String getTag();
-    method public final androidx.fragment.app.Fragment getTargetFragment();
-    method public final int getTargetRequestCode();
-    method public final java.lang.CharSequence getText(int);
-    method public boolean getUserVisibleHint();
-    method public android.view.View getView();
-    method public androidx.lifecycle.ViewModelStore getViewModelStore();
-    method public final int hashCode();
-    method public static androidx.fragment.app.Fragment instantiate(android.content.Context, java.lang.String);
-    method public static androidx.fragment.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
-    method public final boolean isAdded();
-    method public final boolean isDetached();
-    method public final boolean isHidden();
-    method public final boolean isInLayout();
-    method public final boolean isRemoving();
-    method public final boolean isResumed();
-    method public final boolean isStateSaved();
-    method public final boolean isVisible();
-    method public void onActivityCreated(android.os.Bundle);
-    method public void onActivityResult(int, int, android.content.Intent);
-    method public void onAttach(android.content.Context);
-    method public deprecated void onAttach(android.app.Activity);
-    method public void onAttachFragment(androidx.fragment.app.Fragment);
-    method public void onConfigurationChanged(android.content.res.Configuration);
-    method public boolean onContextItemSelected(android.view.MenuItem);
-    method public void onCreate(android.os.Bundle);
-    method public android.view.animation.Animation onCreateAnimation(int, boolean, int);
-    method public android.animation.Animator onCreateAnimator(int, boolean, int);
-    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
-    method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
-    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDestroy();
-    method public void onDestroyOptionsMenu();
-    method public void onDestroyView();
-    method public void onDetach();
-    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle);
-    method public void onHiddenChanged(boolean);
-    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
-    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
-    method public void onLowMemory();
-    method public void onMultiWindowModeChanged(boolean);
-    method public boolean onOptionsItemSelected(android.view.MenuItem);
-    method public void onOptionsMenuClosed(android.view.Menu);
-    method public void onPause();
-    method public void onPictureInPictureModeChanged(boolean);
-    method public void onPrepareOptionsMenu(android.view.Menu);
-    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
-    method public void onResume();
-    method public void onSaveInstanceState(android.os.Bundle);
-    method public void onStart();
-    method public void onStop();
-    method public void onViewCreated(android.view.View, android.os.Bundle);
-    method public void onViewStateRestored(android.os.Bundle);
-    method public void postponeEnterTransition();
-    method public void registerForContextMenu(android.view.View);
-    method public final void requestPermissions(java.lang.String[], int);
-    method public final androidx.fragment.app.FragmentActivity requireActivity();
-    method public final android.content.Context requireContext();
-    method public final androidx.fragment.app.FragmentManager requireFragmentManager();
-    method public final java.lang.Object requireHost();
-    method public void setAllowEnterTransitionOverlap(boolean);
-    method public void setAllowReturnTransitionOverlap(boolean);
-    method public void setArguments(android.os.Bundle);
-    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback);
-    method public void setEnterTransition(java.lang.Object);
-    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback);
-    method public void setExitTransition(java.lang.Object);
-    method public void setHasOptionsMenu(boolean);
-    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState);
-    method public void setMenuVisibility(boolean);
-    method public void setReenterTransition(java.lang.Object);
-    method public void setRetainInstance(boolean);
-    method public void setReturnTransition(java.lang.Object);
-    method public void setSharedElementEnterTransition(java.lang.Object);
-    method public void setSharedElementReturnTransition(java.lang.Object);
-    method public void setTargetFragment(androidx.fragment.app.Fragment, int);
-    method public void setUserVisibleHint(boolean);
-    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
-    method public void startActivity(android.content.Intent);
-    method public void startActivity(android.content.Intent, android.os.Bundle);
-    method public void startActivityForResult(android.content.Intent, int);
-    method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
-    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public void startPostponedEnterTransition();
-    method public void unregisterForContextMenu(android.view.View);
-  }
-
-  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
-    ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
-  }
-
-  public static class Fragment.SavedState implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState> CREATOR;
-  }
-
-  public class FragmentActivity extends androidx.core.app.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator androidx.lifecycle.ViewModelStoreOwner {
-    ctor public FragmentActivity();
-    method public java.lang.Object getLastCustomNonConfigurationInstance();
-    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
-    method public androidx.loader.app.LoaderManager getSupportLoaderManager();
-    method public androidx.lifecycle.ViewModelStore getViewModelStore();
-    method public void onAttachFragment(androidx.fragment.app.Fragment);
-    method public void onMultiWindowModeChanged(boolean);
-    method public void onPictureInPictureModeChanged(boolean);
-    method protected void onResumeFragments();
-    method public java.lang.Object onRetainCustomNonConfigurationInstance();
-    method public final java.lang.Object onRetainNonConfigurationInstance();
-    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback);
-    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback);
-    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
-    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle);
-    method public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public void supportFinishAfterTransition();
-    method public deprecated void supportInvalidateOptionsMenu();
-    method public void supportPostponeEnterTransition();
-    method public void supportStartPostponedEnterTransition();
-    method public final void validateRequestPermissionsRequestCode(int);
-  }
-
-  public abstract class FragmentContainer {
-    ctor public FragmentContainer();
-    method public androidx.fragment.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
-    method public abstract android.view.View onFindViewById(int);
-    method public abstract boolean onHasView();
-  }
-
-  public class FragmentController {
-    method public void attachHost(androidx.fragment.app.Fragment);
-    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
-    method public void dispatchActivityCreated();
-    method public void dispatchConfigurationChanged(android.content.res.Configuration);
-    method public boolean dispatchContextItemSelected(android.view.MenuItem);
-    method public void dispatchCreate();
-    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
-    method public void dispatchDestroy();
-    method public void dispatchDestroyView();
-    method public void dispatchLowMemory();
-    method public void dispatchMultiWindowModeChanged(boolean);
-    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
-    method public void dispatchOptionsMenuClosed(android.view.Menu);
-    method public void dispatchPause();
-    method public void dispatchPictureInPictureModeChanged(boolean);
-    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
-    method public void dispatchReallyStop();
-    method public void dispatchResume();
-    method public void dispatchStart();
-    method public void dispatchStop();
-    method public deprecated void doLoaderDestroy();
-    method public deprecated void doLoaderRetain();
-    method public deprecated void doLoaderStart();
-    method public deprecated void doLoaderStop(boolean);
-    method public deprecated void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public boolean execPendingActions();
-    method public androidx.fragment.app.Fragment findFragmentByWho(java.lang.String);
-    method public java.util.List<androidx.fragment.app.Fragment> getActiveFragments(java.util.List<androidx.fragment.app.Fragment>);
-    method public int getActiveFragmentsCount();
-    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
-    method public deprecated androidx.loader.app.LoaderManager getSupportLoaderManager();
-    method public void noteStateNotSaved();
-    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
-    method public deprecated void reportLoaderStart();
-    method public deprecated void restoreAllState(android.os.Parcelable, java.util.List<androidx.fragment.app.Fragment>);
-    method public void restoreAllState(android.os.Parcelable, androidx.fragment.app.FragmentManagerNonConfig);
-    method public deprecated void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String, androidx.loader.app.LoaderManager>);
-    method public deprecated androidx.collection.SimpleArrayMap<java.lang.String, androidx.loader.app.LoaderManager> retainLoaderNonConfig();
-    method public androidx.fragment.app.FragmentManagerNonConfig retainNestedNonConfig();
-    method public deprecated java.util.List<androidx.fragment.app.Fragment> retainNonConfig();
-    method public android.os.Parcelable saveAllState();
-  }
-
-  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
-    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
-    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public android.view.View onFindViewById(int);
-    method public abstract E onGetHost();
-    method public android.view.LayoutInflater onGetLayoutInflater();
-    method public int onGetWindowAnimations();
-    method public boolean onHasView();
-    method public boolean onHasWindowAnimations();
-    method public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, java.lang.String[], int);
-    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
-    method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
-    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
-    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle);
-    method public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public void onSupportInvalidateOptionsMenu();
-  }
-
-  public abstract class FragmentManager {
-    ctor public FragmentManager();
-    method public abstract void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
-    method public abstract androidx.fragment.app.FragmentTransaction beginTransaction();
-    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public static void enableDebugLogging(boolean);
-    method public abstract boolean executePendingTransactions();
-    method public abstract androidx.fragment.app.Fragment findFragmentById(int);
-    method public abstract androidx.fragment.app.Fragment findFragmentByTag(java.lang.String);
-    method public abstract androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
-    method public abstract int getBackStackEntryCount();
-    method public abstract androidx.fragment.app.Fragment getFragment(android.os.Bundle, java.lang.String);
-    method public abstract java.util.List<androidx.fragment.app.Fragment> getFragments();
-    method public abstract androidx.fragment.app.Fragment getPrimaryNavigationFragment();
-    method public abstract boolean isDestroyed();
-    method public abstract boolean isStateSaved();
-    method public abstract void popBackStack();
-    method public abstract void popBackStack(java.lang.String, int);
-    method public abstract void popBackStack(int, int);
-    method public abstract boolean popBackStackImmediate();
-    method public abstract boolean popBackStackImmediate(java.lang.String, int);
-    method public abstract boolean popBackStackImmediate(int, int);
-    method public abstract void putFragment(android.os.Bundle, java.lang.String, androidx.fragment.app.Fragment);
-    method public abstract void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
-    method public abstract void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
-    method public abstract androidx.fragment.app.Fragment.SavedState saveFragmentInstanceState(androidx.fragment.app.Fragment);
-    method public abstract void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
-    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
-  }
-
-  public static abstract interface FragmentManager.BackStackEntry {
-    method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
-    method public abstract int getBreadCrumbShortTitleRes();
-    method public abstract java.lang.CharSequence getBreadCrumbTitle();
-    method public abstract int getBreadCrumbTitleRes();
-    method public abstract int getId();
-    method public abstract java.lang.String getName();
-  }
-
-  public static abstract class FragmentManager.FragmentLifecycleCallbacks {
-    ctor public FragmentManager.FragmentLifecycleCallbacks();
-    method public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
-    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
-    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
-    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
-    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
-    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
-    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle);
-    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
-  }
-
-  public static abstract interface FragmentManager.OnBackStackChangedListener {
-    method public abstract void onBackStackChanged();
-  }
-
-  public class FragmentManagerNonConfig {
-  }
-
-  public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
-    ctor public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
-    method public abstract androidx.fragment.app.Fragment getItem(int);
-    method public long getItemId(int);
-    method public boolean isViewFromObject(android.view.View, java.lang.Object);
-  }
-
-  public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
-    ctor public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
-    method public abstract androidx.fragment.app.Fragment getItem(int);
-    method public boolean isViewFromObject(android.view.View, java.lang.Object);
-  }
-
-  public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
-    ctor public FragmentTabHost(android.content.Context);
-    ctor public FragmentTabHost(android.content.Context, android.util.AttributeSet);
-    method public void addTab(android.widget.TabHost.TabSpec, java.lang.Class<?>, android.os.Bundle);
-    method public void onTabChanged(java.lang.String);
-    method public deprecated void setup();
-    method public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
-    method public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
-  }
-
-  public abstract class FragmentTransaction {
-    ctor public FragmentTransaction();
-    method public abstract androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, java.lang.String);
-    method public abstract androidx.fragment.app.FragmentTransaction add(int, androidx.fragment.app.Fragment);
-    method public abstract androidx.fragment.app.FragmentTransaction add(int, androidx.fragment.app.Fragment, java.lang.String);
-    method public abstract androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
-    method public abstract androidx.fragment.app.FragmentTransaction addToBackStack(java.lang.String);
-    method public abstract androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
-    method public abstract int commit();
-    method public abstract int commitAllowingStateLoss();
-    method public abstract void commitNow();
-    method public abstract void commitNowAllowingStateLoss();
-    method public abstract androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
-    method public abstract androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
-    method public abstract androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
-    method public abstract boolean isAddToBackStackAllowed();
-    method public abstract boolean isEmpty();
-    method public abstract androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
-    method public abstract androidx.fragment.app.FragmentTransaction replace(int, androidx.fragment.app.Fragment);
-    method public abstract androidx.fragment.app.FragmentTransaction replace(int, androidx.fragment.app.Fragment, java.lang.String);
-    method public abstract androidx.fragment.app.FragmentTransaction runOnCommit(java.lang.Runnable);
-    method public abstract deprecated androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
-    method public abstract androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(int);
-    method public abstract androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
-    method public abstract androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(int);
-    method public abstract androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
-    method public abstract androidx.fragment.app.FragmentTransaction setCustomAnimations(int, int);
-    method public abstract androidx.fragment.app.FragmentTransaction setCustomAnimations(int, int, int, int);
-    method public abstract androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment);
-    method public abstract androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
-    method public abstract androidx.fragment.app.FragmentTransaction setTransition(int);
-    method public abstract androidx.fragment.app.FragmentTransaction setTransitionStyle(int);
-    method public abstract androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
-    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
-    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
-    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
-    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
-    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
-    field public static final int TRANSIT_NONE = 0; // 0x0
-    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
-  }
-
-  public class ListFragment extends androidx.fragment.app.Fragment {
-    ctor public ListFragment();
-    method public android.widget.ListAdapter getListAdapter();
-    method public android.widget.ListView getListView();
-    method public long getSelectedItemId();
-    method public int getSelectedItemPosition();
-    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
-    method public void setEmptyText(java.lang.CharSequence);
-    method public void setListAdapter(android.widget.ListAdapter);
-    method public void setListShown(boolean);
-    method public void setListShownNoAnimation(boolean);
-    method public void setSelection(int);
-  }
-}
-
diff --git a/glance/glance-appwidget-preview/src/main/java/androidx/glance/appwidget/preview/ComposableInvoker.kt b/glance/glance-appwidget-preview/src/main/java/androidx/glance/appwidget/preview/ComposableInvoker.kt
index 6ed4e8a..8505a8f 100644
--- a/glance/glance-appwidget-preview/src/main/java/androidx/glance/appwidget/preview/ComposableInvoker.kt
+++ b/glance/glance-appwidget-preview/src/main/java/androidx/glance/appwidget/preview/ComposableInvoker.kt
@@ -131,7 +131,7 @@
                 changedParams +
                 defaultParams ==
                 totalParams
-        )
+        ) { "invalid param count" }
 
         val changedStartIndex = composerIndex + 1
         val defaultStartIndex = changedStartIndex + changedParams
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
index 2638da4..22a7cc9 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidget.kt
@@ -88,7 +88,7 @@
         context: Context,
         id: GlanceId
     ) {
-        require(id is AppWidgetId)
+        require(id is AppWidgetId) { "Invalid Glance ID" }
         update(context, id.appWidgetId)
     }
 
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetManager.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetManager.kt
index 6c4aedb..41c7633 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetManager.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetManager.kt
@@ -70,8 +70,8 @@
         receiver: R,
         provider: P,
     ) {
-        val receiverName = requireNotNull(receiver.javaClass.canonicalName)
-        val providerName = requireNotNull(provider.javaClass.canonicalName)
+        val receiverName = requireNotNull(receiver.javaClass.canonicalName) { "no receiver name" }
+        val providerName = requireNotNull(provider.javaClass.canonicalName) { "no provider name" }
         dataStore.updateData { pref ->
             pref.toMutablePreferences().also { builder ->
                 builder[providersKey] = (pref[providersKey] ?: emptySet()) + receiverName
@@ -100,7 +100,7 @@
      */
     suspend fun <T : GlanceAppWidget> getGlanceIds(provider: Class<T>): List<GlanceId> {
         val state = getState()
-        val providerName = requireNotNull(provider.canonicalName)
+        val providerName = requireNotNull(provider.canonicalName) { "no canonical provider name" }
         val receivers = state.providerNameToReceivers[providerName] ?: return emptyList()
         return receivers.flatMap { receiver ->
             appWidgetManager.getAppWidgetIds(receiver).map { AppWidgetId(it) }
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetReceiver.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetReceiver.kt
index 964fa8d..30816d7 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetReceiver.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/GlanceAppWidgetReceiver.kt
@@ -144,8 +144,10 @@
             when (intent.action) {
                 Intent.ACTION_LOCALE_CHANGED, ACTION_DEBUG_UPDATE -> {
                     val appWidgetManager = AppWidgetManager.getInstance(context)
-                    val componentName =
-                        ComponentName(context.packageName, checkNotNull(javaClass.canonicalName))
+                    val componentName = ComponentName(
+                        context.packageName,
+                        checkNotNull(javaClass.canonicalName) { "no canonical name" }
+                    )
                     val ids = if (intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS)) {
                         intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS)!!
                     } else {
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/RemoteViewsTranslator.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/RemoteViewsTranslator.kt
index 2618cbc..d94e52f 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/RemoteViewsTranslator.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/RemoteViewsTranslator.kt
@@ -128,7 +128,7 @@
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                     Api31Impl.createRemoteViews(views.toMap())
                 } else {
-                    require(views.size == 1 || views.size == 2)
+                    require(views.size == 1 || views.size == 2) { "unsupported views size" }
                     combineLandscapeAndPortrait(views.map { it.second })
                 }
             }
diff --git a/glance/glance-wear-tiles-preview/src/main/java/androidx/glance/wear/tiles/preview/ComposableInvoker.kt b/glance/glance-wear-tiles-preview/src/main/java/androidx/glance/wear/tiles/preview/ComposableInvoker.kt
index 6f9269c..4fc04d9 100644
--- a/glance/glance-wear-tiles-preview/src/main/java/androidx/glance/wear/tiles/preview/ComposableInvoker.kt
+++ b/glance/glance-wear-tiles-preview/src/main/java/androidx/glance/wear/tiles/preview/ComposableInvoker.kt
@@ -131,7 +131,7 @@
                 changedParams +
                 defaultParams ==
                 totalParams
-        )
+        ) { "invalid param count" }
 
         val changedStartIndex = composerIndex + 1
         val defaultStartIndex = changedStartIndex + changedParams
diff --git a/leanback/leanback/api/0.0.0.txt b/leanback/leanback/api/0.0.0.txt
deleted file mode 100644
index 7224729..0000000
--- a/leanback/leanback/api/0.0.0.txt
+++ /dev/null
@@ -1,3104 +0,0 @@
-package androidx.leanback.app {
-
-  public final class BackgroundManager {
-    method public void attach(android.view.Window);
-    method public void attachToView(android.view.View);
-    method public void clearDrawable();
-    method public int getColor();
-    method public deprecated android.graphics.drawable.Drawable getDefaultDimLayer();
-    method public deprecated android.graphics.drawable.Drawable getDimLayer();
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public static androidx.leanback.app.BackgroundManager getInstance(android.app.Activity);
-    method public boolean isAttached();
-    method public boolean isAutoReleaseOnStop();
-    method public void release();
-    method public void setAutoReleaseOnStop(boolean);
-    method public void setBitmap(android.graphics.Bitmap);
-    method public void setColor(int);
-    method public deprecated void setDimLayer(android.graphics.drawable.Drawable);
-    method public void setDrawable(android.graphics.drawable.Drawable);
-    method public void setThemeDrawableResourceId(int);
-  }
-
-  public deprecated class BaseFragment extends androidx.leanback.app.BrandedFragment {
-    method protected java.lang.Object createEntranceTransition();
-    method public final androidx.leanback.app.ProgressBarManager getProgressBarManager();
-    method protected void onEntranceTransitionEnd();
-    method protected void onEntranceTransitionPrepare();
-    method protected void onEntranceTransitionStart();
-    method public void prepareEntranceTransition();
-    method protected void runEntranceTransition(java.lang.Object);
-    method public void startEntranceTransition();
-  }
-
-  public class BaseSupportFragment extends androidx.leanback.app.BrandedSupportFragment {
-    method protected java.lang.Object createEntranceTransition();
-    method public final androidx.leanback.app.ProgressBarManager getProgressBarManager();
-    method protected void onEntranceTransitionEnd();
-    method protected void onEntranceTransitionPrepare();
-    method protected void onEntranceTransitionStart();
-    method public void prepareEntranceTransition();
-    method protected void runEntranceTransition(java.lang.Object);
-    method public void startEntranceTransition();
-  }
-
-  public deprecated class BrandedFragment extends android.app.Fragment {
-    ctor public BrandedFragment();
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public int getSearchAffordanceColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
-    method public java.lang.CharSequence getTitle();
-    method public android.view.View getTitleView();
-    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
-    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public final boolean isShowingTitle();
-    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
-    method public void setSearchAffordanceColor(int);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleView(android.view.View);
-    method public void showTitle(boolean);
-    method public void showTitle(int);
-  }
-
-  public class BrandedSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public BrandedSupportFragment();
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public int getSearchAffordanceColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
-    method public java.lang.CharSequence getTitle();
-    method public android.view.View getTitleView();
-    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
-    method public void installTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public final boolean isShowingTitle();
-    method public android.view.View onInflateTitleView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
-    method public void setSearchAffordanceColor(int);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleView(android.view.View);
-    method public void showTitle(boolean);
-    method public void showTitle(int);
-  }
-
-  public deprecated class BrowseFragment extends androidx.leanback.app.BaseFragment {
-    ctor public BrowseFragment();
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
-    method public void enableMainFragmentScaling(boolean);
-    method public deprecated void enableRowScaling(boolean);
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public int getBrandColor();
-    method public androidx.leanback.app.HeadersFragment getHeadersFragment();
-    method public int getHeadersState();
-    method public android.app.Fragment getMainFragment();
-    method public final androidx.leanback.app.BrowseFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
-    method public androidx.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public androidx.leanback.app.RowsFragment getRowsFragment();
-    method public int getSelectedPosition();
-    method public androidx.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
-    method public final boolean isHeadersTransitionOnBackEnabled();
-    method public boolean isInHeadersTransition();
-    method public boolean isShowingHeaders();
-    method public androidx.leanback.app.HeadersFragment onCreateHeadersFragment();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setBrandColor(int);
-    method public void setBrowseTransitionListener(androidx.leanback.app.BrowseFragment.BrowseTransitionListener);
-    method public void setHeaderPresenterSelector(androidx.leanback.widget.PresenterSelector);
-    method public void setHeadersState(int);
-    method public final void setHeadersTransitionOnBackEnabled(boolean);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-    method public void startHeadersTransition(boolean);
-    field public static final int HEADERS_DISABLED = 3; // 0x3
-    field public static final int HEADERS_ENABLED = 1; // 0x1
-    field public static final int HEADERS_HIDDEN = 2; // 0x2
-  }
-
-  public static deprecated class BrowseFragment.BrowseTransitionListener {
-    ctor public BrowseFragment.BrowseTransitionListener();
-    method public void onHeadersTransitionStart(boolean);
-    method public void onHeadersTransitionStop(boolean);
-  }
-
-  public static abstract deprecated class BrowseFragment.FragmentFactory<T extends android.app.Fragment> {
-    ctor public BrowseFragment.FragmentFactory();
-    method public abstract T createFragment(java.lang.Object);
-  }
-
-  public static abstract deprecated interface BrowseFragment.FragmentHost {
-    method public abstract void notifyDataReady(androidx.leanback.app.BrowseFragment.MainFragmentAdapter);
-    method public abstract void notifyViewCreated(androidx.leanback.app.BrowseFragment.MainFragmentAdapter);
-    method public abstract void showTitleView(boolean);
-  }
-
-  public static deprecated class BrowseFragment.ListRowFragmentFactory extends androidx.leanback.app.BrowseFragment.FragmentFactory {
-    ctor public BrowseFragment.ListRowFragmentFactory();
-    method public androidx.leanback.app.RowsFragment createFragment(java.lang.Object);
-  }
-
-  public static deprecated class BrowseFragment.MainFragmentAdapter<T extends android.app.Fragment> {
-    ctor public BrowseFragment.MainFragmentAdapter(T);
-    method public final T getFragment();
-    method public final androidx.leanback.app.BrowseFragment.FragmentHost getFragmentHost();
-    method public boolean isScalingEnabled();
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public boolean onTransitionPrepare();
-    method public void onTransitionStart();
-    method public void setAlignment(int);
-    method public void setEntranceTransitionState(boolean);
-    method public void setExpand(boolean);
-    method public void setScalingEnabled(boolean);
-  }
-
-  public static abstract deprecated interface BrowseFragment.MainFragmentAdapterProvider {
-    method public abstract androidx.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
-  }
-
-  public static final deprecated class BrowseFragment.MainFragmentAdapterRegistry {
-    ctor public BrowseFragment.MainFragmentAdapterRegistry();
-    method public android.app.Fragment createFragment(java.lang.Object);
-    method public void registerFragment(java.lang.Class, androidx.leanback.app.BrowseFragment.FragmentFactory);
-  }
-
-  public static deprecated class BrowseFragment.MainFragmentRowsAdapter<T extends android.app.Fragment> {
-    ctor public BrowseFragment.MainFragmentRowsAdapter(T);
-    method public androidx.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
-    method public final T getFragment();
-    method public int getSelectedPosition();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-    method public void setSelectedPosition(int, boolean);
-  }
-
-  public static abstract deprecated interface BrowseFragment.MainFragmentRowsAdapterProvider {
-    method public abstract androidx.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-  }
-
-  public class BrowseSupportFragment extends androidx.leanback.app.BaseSupportFragment {
-    ctor public BrowseSupportFragment();
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, int);
-    method public void enableMainFragmentScaling(boolean);
-    method public deprecated void enableRowScaling(boolean);
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public int getBrandColor();
-    method public int getHeadersState();
-    method public androidx.leanback.app.HeadersSupportFragment getHeadersSupportFragment();
-    method public androidx.fragment.app.Fragment getMainFragment();
-    method public final androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
-    method public androidx.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public androidx.leanback.app.RowsSupportFragment getRowsSupportFragment();
-    method public int getSelectedPosition();
-    method public androidx.leanback.widget.RowPresenter.ViewHolder getSelectedRowViewHolder();
-    method public final boolean isHeadersTransitionOnBackEnabled();
-    method public boolean isInHeadersTransition();
-    method public boolean isShowingHeaders();
-    method public androidx.leanback.app.HeadersSupportFragment onCreateHeadersSupportFragment();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setBrandColor(int);
-    method public void setBrowseTransitionListener(androidx.leanback.app.BrowseSupportFragment.BrowseTransitionListener);
-    method public void setHeaderPresenterSelector(androidx.leanback.widget.PresenterSelector);
-    method public void setHeadersState(int);
-    method public final void setHeadersTransitionOnBackEnabled(boolean);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-    method public void startHeadersTransition(boolean);
-    field public static final int HEADERS_DISABLED = 3; // 0x3
-    field public static final int HEADERS_ENABLED = 1; // 0x1
-    field public static final int HEADERS_HIDDEN = 2; // 0x2
-  }
-
-  public static class BrowseSupportFragment.BrowseTransitionListener {
-    ctor public BrowseSupportFragment.BrowseTransitionListener();
-    method public void onHeadersTransitionStart(boolean);
-    method public void onHeadersTransitionStop(boolean);
-  }
-
-  public static abstract class BrowseSupportFragment.FragmentFactory<T extends androidx.fragment.app.Fragment> {
-    ctor public BrowseSupportFragment.FragmentFactory();
-    method public abstract T createFragment(java.lang.Object);
-  }
-
-  public static abstract interface BrowseSupportFragment.FragmentHost {
-    method public abstract void notifyDataReady(androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
-    method public abstract void notifyViewCreated(androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapter);
-    method public abstract void showTitleView(boolean);
-  }
-
-  public static class BrowseSupportFragment.ListRowFragmentFactory extends androidx.leanback.app.BrowseSupportFragment.FragmentFactory {
-    ctor public BrowseSupportFragment.ListRowFragmentFactory();
-    method public androidx.leanback.app.RowsSupportFragment createFragment(java.lang.Object);
-  }
-
-  public static class BrowseSupportFragment.MainFragmentAdapter<T extends androidx.fragment.app.Fragment> {
-    ctor public BrowseSupportFragment.MainFragmentAdapter(T);
-    method public final T getFragment();
-    method public final androidx.leanback.app.BrowseSupportFragment.FragmentHost getFragmentHost();
-    method public boolean isScalingEnabled();
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public boolean onTransitionPrepare();
-    method public void onTransitionStart();
-    method public void setAlignment(int);
-    method public void setEntranceTransitionState(boolean);
-    method public void setExpand(boolean);
-    method public void setScalingEnabled(boolean);
-  }
-
-  public static abstract interface BrowseSupportFragment.MainFragmentAdapterProvider {
-    method public abstract androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
-  }
-
-  public static final class BrowseSupportFragment.MainFragmentAdapterRegistry {
-    ctor public BrowseSupportFragment.MainFragmentAdapterRegistry();
-    method public androidx.fragment.app.Fragment createFragment(java.lang.Object);
-    method public void registerFragment(java.lang.Class, androidx.leanback.app.BrowseSupportFragment.FragmentFactory);
-  }
-
-  public static class BrowseSupportFragment.MainFragmentRowsAdapter<T extends androidx.fragment.app.Fragment> {
-    ctor public BrowseSupportFragment.MainFragmentRowsAdapter(T);
-    method public androidx.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
-    method public final T getFragment();
-    method public int getSelectedPosition();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-    method public void setSelectedPosition(int, boolean);
-  }
-
-  public static abstract interface BrowseSupportFragment.MainFragmentRowsAdapterProvider {
-    method public abstract androidx.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-  }
-
-  public deprecated class DetailsFragment extends androidx.leanback.app.BaseFragment {
-    ctor public DetailsFragment();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public androidx.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.DetailsParallax getParallax();
-    method public androidx.leanback.app.RowsFragment getRowsFragment();
-    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method protected void onSetDetailsOverviewRowStatus(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
-    method protected void onSetRowStatus(androidx.leanback.widget.RowPresenter, androidx.leanback.widget.RowPresenter.ViewHolder, int, int, int);
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method protected void setupDetailsOverviewRowPresenter(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter);
-    method protected void setupPresenter(androidx.leanback.widget.Presenter);
-  }
-
-  public deprecated class DetailsFragmentBackgroundController {
-    ctor public DetailsFragmentBackgroundController(androidx.leanback.app.DetailsFragment);
-    method public boolean canNavigateToVideoFragment();
-    method public void enableParallax();
-    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, androidx.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
-    method public final android.app.Fragment findOrCreateVideoFragment();
-    method public final android.graphics.drawable.Drawable getBottomDrawable();
-    method public final android.graphics.Bitmap getCoverBitmap();
-    method public final android.graphics.drawable.Drawable getCoverDrawable();
-    method public final int getParallaxDrawableMaxOffset();
-    method public final androidx.leanback.media.PlaybackGlue getPlaybackGlue();
-    method public final int getSolidColor();
-    method public androidx.leanback.media.PlaybackGlueHost onCreateGlueHost();
-    method public android.app.Fragment onCreateVideoFragment();
-    method public final void setCoverBitmap(android.graphics.Bitmap);
-    method public final void setParallaxDrawableMaxOffset(int);
-    method public final void setSolidColor(int);
-    method public void setupVideoPlayback(androidx.leanback.media.PlaybackGlue);
-    method public final void switchToRows();
-    method public final void switchToVideo();
-  }
-
-  public class DetailsSupportFragment extends androidx.leanback.app.BaseSupportFragment {
-    ctor public DetailsSupportFragment();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public androidx.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.DetailsParallax getParallax();
-    method public androidx.leanback.app.RowsSupportFragment getRowsSupportFragment();
-    method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method protected void onSetDetailsOverviewRowStatus(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int);
-    method protected void onSetRowStatus(androidx.leanback.widget.RowPresenter, androidx.leanback.widget.RowPresenter.ViewHolder, int, int, int);
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method protected void setupDetailsOverviewRowPresenter(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter);
-    method protected void setupPresenter(androidx.leanback.widget.Presenter);
-  }
-
-  public class DetailsSupportFragmentBackgroundController {
-    ctor public DetailsSupportFragmentBackgroundController(androidx.leanback.app.DetailsSupportFragment);
-    method public boolean canNavigateToVideoSupportFragment();
-    method public void enableParallax();
-    method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, androidx.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
-    method public final androidx.fragment.app.Fragment findOrCreateVideoSupportFragment();
-    method public final android.graphics.drawable.Drawable getBottomDrawable();
-    method public final android.graphics.Bitmap getCoverBitmap();
-    method public final android.graphics.drawable.Drawable getCoverDrawable();
-    method public final int getParallaxDrawableMaxOffset();
-    method public final androidx.leanback.media.PlaybackGlue getPlaybackGlue();
-    method public final int getSolidColor();
-    method public androidx.leanback.media.PlaybackGlueHost onCreateGlueHost();
-    method public androidx.fragment.app.Fragment onCreateVideoSupportFragment();
-    method public final void setCoverBitmap(android.graphics.Bitmap);
-    method public final void setParallaxDrawableMaxOffset(int);
-    method public final void setSolidColor(int);
-    method public void setupVideoPlayback(androidx.leanback.media.PlaybackGlue);
-    method public final void switchToRows();
-    method public final void switchToVideo();
-  }
-
-  public deprecated class ErrorFragment extends androidx.leanback.app.BrandedFragment {
-    ctor public ErrorFragment();
-    method public android.graphics.drawable.Drawable getBackgroundDrawable();
-    method public android.view.View.OnClickListener getButtonClickListener();
-    method public java.lang.String getButtonText();
-    method public android.graphics.drawable.Drawable getImageDrawable();
-    method public java.lang.CharSequence getMessage();
-    method public boolean isBackgroundTranslucent();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setButtonClickListener(android.view.View.OnClickListener);
-    method public void setButtonText(java.lang.String);
-    method public void setDefaultBackground(boolean);
-    method public void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setMessage(java.lang.CharSequence);
-  }
-
-  public class ErrorSupportFragment extends androidx.leanback.app.BrandedSupportFragment {
-    ctor public ErrorSupportFragment();
-    method public android.graphics.drawable.Drawable getBackgroundDrawable();
-    method public android.view.View.OnClickListener getButtonClickListener();
-    method public java.lang.String getButtonText();
-    method public android.graphics.drawable.Drawable getImageDrawable();
-    method public java.lang.CharSequence getMessage();
-    method public boolean isBackgroundTranslucent();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setButtonClickListener(android.view.View.OnClickListener);
-    method public void setButtonText(java.lang.String);
-    method public void setDefaultBackground(boolean);
-    method public void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setMessage(java.lang.CharSequence);
-  }
-
-  public deprecated class GuidedStepFragment extends android.app.Fragment {
-    ctor public GuidedStepFragment();
-    method public static int add(android.app.FragmentManager, androidx.leanback.app.GuidedStepFragment);
-    method public static int add(android.app.FragmentManager, androidx.leanback.app.GuidedStepFragment, int);
-    method public static int addAsRoot(android.app.Activity, androidx.leanback.app.GuidedStepFragment, int);
-    method public void collapseAction(boolean);
-    method public void collapseSubActions();
-    method public void expandAction(androidx.leanback.widget.GuidedAction, boolean);
-    method public void expandSubActions(androidx.leanback.widget.GuidedAction);
-    method public androidx.leanback.widget.GuidedAction findActionById(long);
-    method public int findActionPositionById(long);
-    method public androidx.leanback.widget.GuidedAction findButtonActionById(long);
-    method public int findButtonActionPositionById(long);
-    method public void finishGuidedStepFragments();
-    method public android.view.View getActionItemView(int);
-    method public java.util.List<androidx.leanback.widget.GuidedAction> getActions();
-    method public android.view.View getButtonActionItemView(int);
-    method public java.util.List<androidx.leanback.widget.GuidedAction> getButtonActions();
-    method public static androidx.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
-    method public androidx.leanback.widget.GuidanceStylist getGuidanceStylist();
-    method public androidx.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
-    method public androidx.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
-    method public int getSelectedActionPosition();
-    method public int getSelectedButtonActionPosition();
-    method public int getUiStyle();
-    method public boolean isExpanded();
-    method public boolean isFocusOutEndAllowed();
-    method public boolean isFocusOutStartAllowed();
-    method public boolean isSubActionsExpanded();
-    method public void notifyActionChanged(int);
-    method public void notifyButtonActionChanged(int);
-    method protected void onAddSharedElementTransition(android.app.FragmentTransaction, androidx.leanback.app.GuidedStepFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction>, android.os.Bundle);
-    method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
-    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction>, android.os.Bundle);
-    method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
-    method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
-    method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
-    method public void onGuidedActionClicked(androidx.leanback.widget.GuidedAction);
-    method public void onGuidedActionEditCanceled(androidx.leanback.widget.GuidedAction);
-    method public deprecated void onGuidedActionEdited(androidx.leanback.widget.GuidedAction);
-    method public long onGuidedActionEditedAndProceed(androidx.leanback.widget.GuidedAction);
-    method public void onGuidedActionFocused(androidx.leanback.widget.GuidedAction);
-    method protected void onProvideFragmentTransitions();
-    method public int onProvideTheme();
-    method public boolean onSubGuidedActionClicked(androidx.leanback.widget.GuidedAction);
-    method public void openInEditMode(androidx.leanback.widget.GuidedAction);
-    method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
-    method public void setActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public void setActionsDiffCallback(androidx.leanback.widget.DiffCallback<androidx.leanback.widget.GuidedAction>);
-    method public void setButtonActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public void setSelectedActionPosition(int);
-    method public void setSelectedButtonActionPosition(int);
-    method public void setUiStyle(int);
-    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
-    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
-    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
-    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
-    field public static final int UI_STYLE_REPLACE = 0; // 0x0
-  }
-
-  public class GuidedStepSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public GuidedStepSupportFragment();
-    method public static int add(androidx.fragment.app.FragmentManager, androidx.leanback.app.GuidedStepSupportFragment);
-    method public static int add(androidx.fragment.app.FragmentManager, androidx.leanback.app.GuidedStepSupportFragment, int);
-    method public static int addAsRoot(androidx.fragment.app.FragmentActivity, androidx.leanback.app.GuidedStepSupportFragment, int);
-    method public void collapseAction(boolean);
-    method public void collapseSubActions();
-    method public void expandAction(androidx.leanback.widget.GuidedAction, boolean);
-    method public void expandSubActions(androidx.leanback.widget.GuidedAction);
-    method public androidx.leanback.widget.GuidedAction findActionById(long);
-    method public int findActionPositionById(long);
-    method public androidx.leanback.widget.GuidedAction findButtonActionById(long);
-    method public int findButtonActionPositionById(long);
-    method public void finishGuidedStepSupportFragments();
-    method public android.view.View getActionItemView(int);
-    method public java.util.List<androidx.leanback.widget.GuidedAction> getActions();
-    method public android.view.View getButtonActionItemView(int);
-    method public java.util.List<androidx.leanback.widget.GuidedAction> getButtonActions();
-    method public static androidx.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(androidx.fragment.app.FragmentManager);
-    method public androidx.leanback.widget.GuidanceStylist getGuidanceStylist();
-    method public androidx.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
-    method public androidx.leanback.widget.GuidedActionsStylist getGuidedButtonActionsStylist();
-    method public int getSelectedActionPosition();
-    method public int getSelectedButtonActionPosition();
-    method public int getUiStyle();
-    method public boolean isExpanded();
-    method public boolean isFocusOutEndAllowed();
-    method public boolean isFocusOutStartAllowed();
-    method public boolean isSubActionsExpanded();
-    method public void notifyActionChanged(int);
-    method public void notifyButtonActionChanged(int);
-    method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction>, android.os.Bundle);
-    method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
-    method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction>, android.os.Bundle);
-    method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
-    method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
-    method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
-    method public void onGuidedActionClicked(androidx.leanback.widget.GuidedAction);
-    method public void onGuidedActionEditCanceled(androidx.leanback.widget.GuidedAction);
-    method public deprecated void onGuidedActionEdited(androidx.leanback.widget.GuidedAction);
-    method public long onGuidedActionEditedAndProceed(androidx.leanback.widget.GuidedAction);
-    method public void onGuidedActionFocused(androidx.leanback.widget.GuidedAction);
-    method protected void onProvideFragmentTransitions();
-    method public int onProvideTheme();
-    method public boolean onSubGuidedActionClicked(androidx.leanback.widget.GuidedAction);
-    method public void openInEditMode(androidx.leanback.widget.GuidedAction);
-    method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
-    method public void setActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public void setActionsDiffCallback(androidx.leanback.widget.DiffCallback<androidx.leanback.widget.GuidedAction>);
-    method public void setButtonActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public void setSelectedActionPosition(int);
-    method public void setSelectedButtonActionPosition(int);
-    method public void setUiStyle(int);
-    field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
-    field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
-    field public static final deprecated int UI_STYLE_DEFAULT = 0; // 0x0
-    field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
-    field public static final int UI_STYLE_REPLACE = 0; // 0x0
-  }
-
-  public deprecated class HeadersFragment extends android.app.Fragment {
-    ctor public HeadersFragment();
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public void onTransitionStart();
-    method public void setOnHeaderClickedListener(androidx.leanback.app.HeadersFragment.OnHeaderClickedListener);
-    method public void setOnHeaderViewSelectedListener(androidx.leanback.app.HeadersFragment.OnHeaderViewSelectedListener);
-  }
-
-  public static abstract deprecated interface HeadersFragment.OnHeaderClickedListener {
-    method public abstract void onHeaderClicked(androidx.leanback.widget.RowHeaderPresenter.ViewHolder, androidx.leanback.widget.Row);
-  }
-
-  public static abstract deprecated interface HeadersFragment.OnHeaderViewSelectedListener {
-    method public abstract void onHeaderSelected(androidx.leanback.widget.RowHeaderPresenter.ViewHolder, androidx.leanback.widget.Row);
-  }
-
-  public class HeadersSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public HeadersSupportFragment();
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public void onTransitionStart();
-    method public void setOnHeaderClickedListener(androidx.leanback.app.HeadersSupportFragment.OnHeaderClickedListener);
-    method public void setOnHeaderViewSelectedListener(androidx.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener);
-  }
-
-  public static abstract interface HeadersSupportFragment.OnHeaderClickedListener {
-    method public abstract void onHeaderClicked(androidx.leanback.widget.RowHeaderPresenter.ViewHolder, androidx.leanback.widget.Row);
-  }
-
-  public static abstract interface HeadersSupportFragment.OnHeaderViewSelectedListener {
-    method public abstract void onHeaderSelected(androidx.leanback.widget.RowHeaderPresenter.ViewHolder, androidx.leanback.widget.Row);
-  }
-
-  public abstract deprecated class OnboardingFragment extends android.app.Fragment {
-    ctor public OnboardingFragment();
-    method public final int getArrowBackgroundColor();
-    method public final int getArrowColor();
-    method protected final int getCurrentPageIndex();
-    method public final int getDescriptionViewTextColor();
-    method public final int getDotBackgroundColor();
-    method public final int getIconResourceId();
-    method public final int getLogoResourceId();
-    method protected abstract int getPageCount();
-    method protected abstract java.lang.CharSequence getPageDescription(int);
-    method protected abstract java.lang.CharSequence getPageTitle(int);
-    method public final java.lang.CharSequence getStartButtonText();
-    method public final int getTitleViewTextColor();
-    method protected final boolean isLogoAnimationFinished();
-    method protected void moveToNextPage();
-    method protected void moveToPreviousPage();
-    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected android.animation.Animator onCreateDescriptionAnimator();
-    method protected android.animation.Animator onCreateEnterAnimation();
-    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected android.animation.Animator onCreateLogoAnimation();
-    method protected android.animation.Animator onCreateTitleAnimator();
-    method protected void onFinishFragment();
-    method protected void onLogoAnimationFinished();
-    method protected void onPageChanged(int, int);
-    method public int onProvideTheme();
-    method public void setArrowBackgroundColor(int);
-    method public void setArrowColor(int);
-    method public void setDescriptionViewTextColor(int);
-    method public void setDotBackgroundColor(int);
-    method public final void setIconResouceId(int);
-    method public final void setLogoResourceId(int);
-    method public void setStartButtonText(java.lang.CharSequence);
-    method public void setTitleViewTextColor(int);
-    method protected final void startEnterAnimation(boolean);
-  }
-
-  public abstract class OnboardingSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public OnboardingSupportFragment();
-    method public final int getArrowBackgroundColor();
-    method public final int getArrowColor();
-    method protected final int getCurrentPageIndex();
-    method public final int getDescriptionViewTextColor();
-    method public final int getDotBackgroundColor();
-    method public final int getIconResourceId();
-    method public final int getLogoResourceId();
-    method protected abstract int getPageCount();
-    method protected abstract java.lang.CharSequence getPageDescription(int);
-    method protected abstract java.lang.CharSequence getPageTitle(int);
-    method public final java.lang.CharSequence getStartButtonText();
-    method public final int getTitleViewTextColor();
-    method protected final boolean isLogoAnimationFinished();
-    method protected void moveToNextPage();
-    method protected void moveToPreviousPage();
-    method protected abstract android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected abstract android.view.View onCreateContentView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected android.animation.Animator onCreateDescriptionAnimator();
-    method protected android.animation.Animator onCreateEnterAnimation();
-    method protected abstract android.view.View onCreateForegroundView(android.view.LayoutInflater, android.view.ViewGroup);
-    method protected android.animation.Animator onCreateLogoAnimation();
-    method protected android.animation.Animator onCreateTitleAnimator();
-    method protected void onFinishFragment();
-    method protected void onLogoAnimationFinished();
-    method protected void onPageChanged(int, int);
-    method public int onProvideTheme();
-    method public void setArrowBackgroundColor(int);
-    method public void setArrowColor(int);
-    method public void setDescriptionViewTextColor(int);
-    method public void setDotBackgroundColor(int);
-    method public final void setIconResouceId(int);
-    method public final void setLogoResourceId(int);
-    method public void setStartButtonText(java.lang.CharSequence);
-    method public void setTitleViewTextColor(int);
-    method protected final void startEnterAnimation(boolean);
-  }
-
-  public deprecated class PlaybackFragment extends android.app.Fragment {
-    ctor public PlaybackFragment();
-    method public deprecated void fadeOut();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public int getBackgroundType();
-    method public androidx.leanback.app.ProgressBarManager getProgressBarManager();
-    method public void hideControlsOverlay(boolean);
-    method public boolean isControlsOverlayAutoHideEnabled();
-    method public boolean isControlsOverlayVisible();
-    method public deprecated boolean isFadingEnabled();
-    method public void notifyPlaybackRowChanged();
-    method protected void onBufferingStateChanged(boolean);
-    method protected void onError(int, java.lang.CharSequence);
-    method protected void onVideoSizeChanged(int, int);
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setBackgroundType(int);
-    method public void setControlsOverlayAutoHideEnabled(boolean);
-    method public deprecated void setFadingEnabled(boolean);
-    method public void setHostCallback(androidx.leanback.media.PlaybackGlueHost.HostCallback);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
-    method public void setOnPlaybackItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setPlaybackRow(androidx.leanback.widget.Row);
-    method public void setPlaybackRowPresenter(androidx.leanback.widget.PlaybackRowPresenter);
-    method public void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method public void showControlsOverlay(boolean);
-    method public void tickle();
-    field public static final int BG_DARK = 1; // 0x1
-    field public static final int BG_LIGHT = 2; // 0x2
-    field public static final int BG_NONE = 0; // 0x0
-  }
-
-  public deprecated class PlaybackFragmentGlueHost extends androidx.leanback.media.PlaybackGlueHost implements androidx.leanback.widget.PlaybackSeekUi {
-    ctor public PlaybackFragmentGlueHost(androidx.leanback.app.PlaybackFragment);
-    method public void fadeOut();
-    method public void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-  }
-
-  public class PlaybackSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public PlaybackSupportFragment();
-    method public deprecated void fadeOut();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public int getBackgroundType();
-    method public androidx.leanback.app.ProgressBarManager getProgressBarManager();
-    method public void hideControlsOverlay(boolean);
-    method public boolean isControlsOverlayAutoHideEnabled();
-    method public boolean isControlsOverlayVisible();
-    method public deprecated boolean isFadingEnabled();
-    method public void notifyPlaybackRowChanged();
-    method protected void onBufferingStateChanged(boolean);
-    method protected void onError(int, java.lang.CharSequence);
-    method protected void onVideoSizeChanged(int, int);
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setBackgroundType(int);
-    method public void setControlsOverlayAutoHideEnabled(boolean);
-    method public deprecated void setFadingEnabled(boolean);
-    method public void setHostCallback(androidx.leanback.media.PlaybackGlueHost.HostCallback);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
-    method public void setOnPlaybackItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setPlaybackRow(androidx.leanback.widget.Row);
-    method public void setPlaybackRowPresenter(androidx.leanback.widget.PlaybackRowPresenter);
-    method public void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, boolean);
-    method public void showControlsOverlay(boolean);
-    method public void tickle();
-    field public static final int BG_DARK = 1; // 0x1
-    field public static final int BG_LIGHT = 2; // 0x2
-    field public static final int BG_NONE = 0; // 0x0
-  }
-
-  public class PlaybackSupportFragmentGlueHost extends androidx.leanback.media.PlaybackGlueHost implements androidx.leanback.widget.PlaybackSeekUi {
-    ctor public PlaybackSupportFragmentGlueHost(androidx.leanback.app.PlaybackSupportFragment);
-    method public void fadeOut();
-    method public void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-  }
-
-  public final class ProgressBarManager {
-    ctor public ProgressBarManager();
-    method public void disableProgressBar();
-    method public void enableProgressBar();
-    method public long getInitialDelay();
-    method public void hide();
-    method public void setInitialDelay(long);
-    method public void setProgressBarView(android.view.View);
-    method public void setRootView(android.view.ViewGroup);
-    method public void show();
-  }
-
-  public deprecated class RowsFragment extends android.app.Fragment implements androidx.leanback.app.BrowseFragment.MainFragmentAdapterProvider androidx.leanback.app.BrowseFragment.MainFragmentRowsAdapterProvider {
-    ctor public RowsFragment();
-    method public deprecated void enableRowScaling(boolean);
-    method protected androidx.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
-    method public androidx.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
-    method public androidx.leanback.app.BrowseFragment.MainFragmentAdapter getMainFragmentAdapter();
-    method public androidx.leanback.app.BrowseFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-    method public androidx.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public androidx.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public boolean onTransitionPrepare();
-    method public void setAlignment(int);
-    method public void setEntranceTransitionState(boolean);
-    method public void setExpand(boolean);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-  }
-
-  public static class RowsFragment.MainFragmentAdapter extends androidx.leanback.app.BrowseFragment.MainFragmentAdapter {
-    ctor public RowsFragment.MainFragmentAdapter(androidx.leanback.app.RowsFragment);
-  }
-
-  public static deprecated class RowsFragment.MainFragmentRowsAdapter extends androidx.leanback.app.BrowseFragment.MainFragmentRowsAdapter {
-    ctor public RowsFragment.MainFragmentRowsAdapter(androidx.leanback.app.RowsFragment);
-  }
-
-  public class RowsSupportFragment extends androidx.fragment.app.Fragment implements androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapterProvider androidx.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapterProvider {
-    ctor public RowsSupportFragment();
-    method public deprecated void enableRowScaling(boolean);
-    method protected androidx.leanback.widget.VerticalGridView findGridViewFromRoot(android.view.View);
-    method public androidx.leanback.widget.RowPresenter.ViewHolder findRowViewHolderByPosition(int);
-    method public androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapter getMainFragmentAdapter();
-    method public androidx.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-    method public androidx.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
-    method public androidx.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public androidx.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(int);
-    method public boolean isScrolling();
-    method public void onTransitionEnd();
-    method public boolean onTransitionPrepare();
-    method public void setAlignment(int);
-    method public void setEntranceTransitionState(boolean);
-    method public void setExpand(boolean);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public void setSelectedPosition(int, boolean, androidx.leanback.widget.Presenter.ViewHolderTask);
-  }
-
-  public static class RowsSupportFragment.MainFragmentAdapter extends androidx.leanback.app.BrowseSupportFragment.MainFragmentAdapter {
-    ctor public RowsSupportFragment.MainFragmentAdapter(androidx.leanback.app.RowsSupportFragment);
-  }
-
-  public static class RowsSupportFragment.MainFragmentRowsAdapter extends androidx.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter {
-    ctor public RowsSupportFragment.MainFragmentRowsAdapter(androidx.leanback.app.RowsSupportFragment);
-  }
-
-  public deprecated class SearchFragment extends android.app.Fragment {
-    ctor public SearchFragment();
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
-    method public void displayCompletions(java.util.List<java.lang.String>);
-    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public android.content.Intent getRecognizerIntent();
-    method public androidx.leanback.app.RowsFragment getRowsFragment();
-    method public java.lang.String getTitle();
-    method public static androidx.leanback.app.SearchFragment newInstance(java.lang.String);
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchAffordanceColorsInListening(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchQuery(java.lang.String, boolean);
-    method public void setSearchQuery(android.content.Intent, boolean);
-    method public void setSearchResultProvider(androidx.leanback.app.SearchFragment.SearchResultProvider);
-    method public deprecated void setSpeechRecognitionCallback(androidx.leanback.widget.SpeechRecognitionCallback);
-    method public void setTitle(java.lang.String);
-    method public void startRecognition();
-  }
-
-  public static abstract interface SearchFragment.SearchResultProvider {
-    method public abstract androidx.leanback.widget.ObjectAdapter getResultsAdapter();
-    method public abstract boolean onQueryTextChange(java.lang.String);
-    method public abstract boolean onQueryTextSubmit(java.lang.String);
-  }
-
-  public class SearchSupportFragment extends androidx.fragment.app.Fragment {
-    ctor public SearchSupportFragment();
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String);
-    method public static android.os.Bundle createArgs(android.os.Bundle, java.lang.String, java.lang.String);
-    method public void displayCompletions(java.util.List<java.lang.String>);
-    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public android.content.Intent getRecognizerIntent();
-    method public androidx.leanback.app.RowsSupportFragment getRowsSupportFragment();
-    method public java.lang.String getTitle();
-    method public static androidx.leanback.app.SearchSupportFragment newInstance(java.lang.String);
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchAffordanceColorsInListening(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchQuery(java.lang.String, boolean);
-    method public void setSearchQuery(android.content.Intent, boolean);
-    method public void setSearchResultProvider(androidx.leanback.app.SearchSupportFragment.SearchResultProvider);
-    method public deprecated void setSpeechRecognitionCallback(androidx.leanback.widget.SpeechRecognitionCallback);
-    method public void setTitle(java.lang.String);
-    method public void startRecognition();
-  }
-
-  public static abstract interface SearchSupportFragment.SearchResultProvider {
-    method public abstract androidx.leanback.widget.ObjectAdapter getResultsAdapter();
-    method public abstract boolean onQueryTextChange(java.lang.String);
-    method public abstract boolean onQueryTextSubmit(java.lang.String);
-  }
-
-  public deprecated class VerticalGridFragment extends androidx.leanback.app.BaseFragment {
-    ctor public VerticalGridFragment();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public androidx.leanback.widget.VerticalGridPresenter getGridPresenter();
-    method public androidx.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-  }
-
-  public class VerticalGridSupportFragment extends androidx.leanback.app.BaseSupportFragment {
-    ctor public VerticalGridSupportFragment();
-    method public androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public androidx.leanback.widget.VerticalGridPresenter getGridPresenter();
-    method public androidx.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public void setSelectedPosition(int);
-  }
-
-  public deprecated class VideoFragment extends androidx.leanback.app.PlaybackFragment {
-    ctor public VideoFragment();
-    method public android.view.SurfaceView getSurfaceView();
-    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
-  }
-
-  public deprecated class VideoFragmentGlueHost extends androidx.leanback.app.PlaybackFragmentGlueHost implements androidx.leanback.media.SurfaceHolderGlueHost {
-    ctor public VideoFragmentGlueHost(androidx.leanback.app.VideoFragment);
-    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
-  }
-
-  public class VideoSupportFragment extends androidx.leanback.app.PlaybackSupportFragment {
-    ctor public VideoSupportFragment();
-    method public android.view.SurfaceView getSurfaceView();
-    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
-  }
-
-  public class VideoSupportFragmentGlueHost extends androidx.leanback.app.PlaybackSupportFragmentGlueHost implements androidx.leanback.media.SurfaceHolderGlueHost {
-    ctor public VideoSupportFragmentGlueHost(androidx.leanback.app.VideoSupportFragment);
-    method public void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
-  }
-
-}
-
-package androidx.leanback.database {
-
-  public abstract class CursorMapper {
-    ctor public CursorMapper();
-    method protected abstract java.lang.Object bind(android.database.Cursor);
-    method protected abstract void bindColumns(android.database.Cursor);
-    method public java.lang.Object convert(android.database.Cursor);
-  }
-
-}
-
-package androidx.leanback.graphics {
-
-  public class BoundsRule {
-    ctor public BoundsRule();
-    ctor public BoundsRule(androidx.leanback.graphics.BoundsRule);
-    method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
-    field public androidx.leanback.graphics.BoundsRule.ValueRule bottom;
-    field public androidx.leanback.graphics.BoundsRule.ValueRule left;
-    field public androidx.leanback.graphics.BoundsRule.ValueRule right;
-    field public androidx.leanback.graphics.BoundsRule.ValueRule top;
-  }
-
-  public static final class BoundsRule.ValueRule {
-    method public static androidx.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
-    method public int getAbsoluteValue();
-    method public float getFraction();
-    method public static androidx.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
-    method public static androidx.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
-    method public void setAbsoluteValue(int);
-    method public void setFraction(float);
-  }
-
-  public final class ColorFilterCache {
-    method public static androidx.leanback.graphics.ColorFilterCache getColorFilterCache(int);
-    method public android.graphics.ColorFilter getFilterForLevel(float);
-  }
-
-  public final class ColorFilterDimmer {
-    method public void applyFilterToView(android.view.View);
-    method public static androidx.leanback.graphics.ColorFilterDimmer create(androidx.leanback.graphics.ColorFilterCache, float, float);
-    method public static androidx.leanback.graphics.ColorFilterDimmer createDefault(android.content.Context);
-    method public android.graphics.ColorFilter getColorFilter();
-    method public android.graphics.Paint getPaint();
-    method public void setActiveLevel(float);
-  }
-
-  public final class ColorOverlayDimmer {
-    method public int applyToColor(int);
-    method public static androidx.leanback.graphics.ColorOverlayDimmer createColorOverlayDimmer(int, float, float);
-    method public static androidx.leanback.graphics.ColorOverlayDimmer createDefault(android.content.Context);
-    method public void drawColorOverlay(android.graphics.Canvas, android.view.View, boolean);
-    method public int getAlpha();
-    method public float getAlphaFloat();
-    method public android.graphics.Paint getPaint();
-    method public boolean needsDraw();
-    method public void setActiveLevel(float);
-  }
-
-  public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
-    ctor public CompositeDrawable();
-    method public void addChildDrawable(android.graphics.drawable.Drawable);
-    method public void draw(android.graphics.Canvas);
-    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
-    method public int getChildCount();
-    method public android.graphics.drawable.Drawable getDrawable(int);
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void removeChild(int);
-    method public void removeDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
-  }
-
-  public static final class CompositeDrawable.ChildDrawable {
-    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, androidx.leanback.graphics.CompositeDrawable);
-    method public androidx.leanback.graphics.BoundsRule getBoundsRule();
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public void recomputeBounds();
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> BOTTOM_ABSOLUTE;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> BOTTOM_FRACTION;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> LEFT_ABSOLUTE;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> LEFT_FRACTION;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> RIGHT_ABSOLUTE;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> RIGHT_FRACTION;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> TOP_ABSOLUTE;
-    field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> TOP_FRACTION;
-  }
-
-  public class FitWidthBitmapDrawable extends android.graphics.drawable.Drawable {
-    ctor public FitWidthBitmapDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.Bitmap getBitmap();
-    method public int getOpacity();
-    method public android.graphics.Rect getSource();
-    method public int getVerticalOffset();
-    method public void setAlpha(int);
-    method public void setBitmap(android.graphics.Bitmap);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setSource(android.graphics.Rect);
-    method public void setVerticalOffset(int);
-    field public static final android.util.Property<androidx.leanback.graphics.FitWidthBitmapDrawable, java.lang.Integer> PROPERTY_VERTICAL_OFFSET;
-  }
-
-}
-
-package androidx.leanback.media {
-
-  public class MediaControllerAdapter extends androidx.leanback.media.PlayerAdapter {
-    ctor public MediaControllerAdapter(android.support.v4.media.session.MediaControllerCompat);
-    method public android.graphics.drawable.Drawable getMediaArt(android.content.Context);
-    method public android.support.v4.media.session.MediaControllerCompat getMediaController();
-    method public java.lang.CharSequence getMediaSubtitle();
-    method public java.lang.CharSequence getMediaTitle();
-    method public void pause();
-    method public void play();
-  }
-
-  public abstract deprecated class MediaControllerGlue extends androidx.leanback.media.PlaybackControlGlue {
-    ctor public MediaControllerGlue(android.content.Context, int[], int[]);
-    method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
-    method public void detach();
-    method public int getCurrentPosition();
-    method public int getCurrentSpeedId();
-    method public android.graphics.drawable.Drawable getMediaArt();
-    method public final android.support.v4.media.session.MediaControllerCompat getMediaController();
-    method public int getMediaDuration();
-    method public java.lang.CharSequence getMediaSubtitle();
-    method public java.lang.CharSequence getMediaTitle();
-    method public long getSupportedActions();
-    method public boolean hasValidMedia();
-    method public boolean isMediaPlaying();
-  }
-
-  public class MediaPlayerAdapter extends androidx.leanback.media.PlayerAdapter {
-    ctor public MediaPlayerAdapter(android.content.Context);
-    method protected boolean onError(int, int);
-    method protected boolean onInfo(int, int);
-    method protected void onSeekComplete();
-    method public void pause();
-    method public void play();
-    method public void release();
-    method public void reset();
-    method public boolean setDataSource(android.net.Uri);
-  }
-
-  public class PlaybackBannerControlGlue<T extends androidx.leanback.media.PlayerAdapter> extends androidx.leanback.media.PlaybackBaseControlGlue {
-    ctor public PlaybackBannerControlGlue(android.content.Context, int[], T);
-    ctor public PlaybackBannerControlGlue(android.content.Context, int[], int[], T);
-    method public int[] getFastForwardSpeeds();
-    method public int[] getRewindSpeeds();
-    method public void onActionClicked(androidx.leanback.widget.Action);
-    method protected androidx.leanback.widget.PlaybackRowPresenter onCreateRowPresenter();
-    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
-    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
-    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
-    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
-    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
-    field public static final int ACTION_REWIND = 32; // 0x20
-    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
-    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
-    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
-    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
-    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
-    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
-    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
-    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
-    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
-    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
-  }
-
-  public abstract class PlaybackBaseControlGlue<T extends androidx.leanback.media.PlayerAdapter> extends androidx.leanback.media.PlaybackGlue implements androidx.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
-    ctor public PlaybackBaseControlGlue(android.content.Context, T);
-    method public android.graphics.drawable.Drawable getArt();
-    method public final long getBufferedPosition();
-    method public androidx.leanback.widget.PlaybackControlsRow getControlsRow();
-    method public long getCurrentPosition();
-    method public final long getDuration();
-    method public androidx.leanback.widget.PlaybackRowPresenter getPlaybackRowPresenter();
-    method public final T getPlayerAdapter();
-    method public java.lang.CharSequence getSubtitle();
-    method public long getSupportedActions();
-    method public java.lang.CharSequence getTitle();
-    method public boolean isControlsOverlayAutoHideEnabled();
-    method public final boolean isPlaying();
-    method public final boolean isPrepared();
-    method protected static void notifyItemChanged(androidx.leanback.widget.ArrayObjectAdapter, java.lang.Object);
-    method protected void onCreatePrimaryActions(androidx.leanback.widget.ArrayObjectAdapter);
-    method protected abstract androidx.leanback.widget.PlaybackRowPresenter onCreateRowPresenter();
-    method protected void onCreateSecondaryActions(androidx.leanback.widget.ArrayObjectAdapter);
-    method protected void onMetadataChanged();
-    method protected void onPlayCompleted();
-    method protected void onPlayStateChanged();
-    method protected void onPreparedStateChanged();
-    method protected void onUpdateBufferedProgress();
-    method protected void onUpdateDuration();
-    method protected void onUpdateProgress();
-    method public final void seekTo(long);
-    method public void setArt(android.graphics.drawable.Drawable);
-    method public void setControlsOverlayAutoHideEnabled(boolean);
-    method public void setControlsRow(androidx.leanback.widget.PlaybackControlsRow);
-    method public void setPlaybackRowPresenter(androidx.leanback.widget.PlaybackRowPresenter);
-    method public void setSubtitle(java.lang.CharSequence);
-    method public void setTitle(java.lang.CharSequence);
-    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
-    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
-    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
-    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
-    field public static final int ACTION_REPEAT = 512; // 0x200
-    field public static final int ACTION_REWIND = 32; // 0x20
-    field public static final int ACTION_SHUFFLE = 1024; // 0x400
-    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
-    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
-  }
-
-  public abstract class PlaybackControlGlue extends androidx.leanback.media.PlaybackGlue implements androidx.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
-    ctor public PlaybackControlGlue(android.content.Context, int[]);
-    ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
-    method public void enableProgressUpdating(boolean);
-    method public androidx.leanback.widget.PlaybackControlsRow getControlsRow();
-    method public deprecated androidx.leanback.widget.PlaybackControlsRowPresenter getControlsRowPresenter();
-    method public abstract int getCurrentPosition();
-    method public abstract int getCurrentSpeedId();
-    method public int[] getFastForwardSpeeds();
-    method public abstract android.graphics.drawable.Drawable getMediaArt();
-    method public abstract int getMediaDuration();
-    method public abstract java.lang.CharSequence getMediaSubtitle();
-    method public abstract java.lang.CharSequence getMediaTitle();
-    method public androidx.leanback.widget.PlaybackRowPresenter getPlaybackRowPresenter();
-    method public int[] getRewindSpeeds();
-    method public abstract long getSupportedActions();
-    method public int getUpdatePeriod();
-    method public abstract boolean hasValidMedia();
-    method public boolean isFadingEnabled();
-    method public abstract boolean isMediaPlaying();
-    method public void onActionClicked(androidx.leanback.widget.Action);
-    method protected void onCreateControlsRowAndPresenter();
-    method protected void onCreatePrimaryActions(androidx.leanback.widget.SparseArrayObjectAdapter);
-    method protected void onCreateSecondaryActions(androidx.leanback.widget.ArrayObjectAdapter);
-    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
-    method protected void onMetadataChanged();
-    method protected void onStateChanged();
-    method public void play(int);
-    method public final void play();
-    method public void setControlsRow(androidx.leanback.widget.PlaybackControlsRow);
-    method public deprecated void setControlsRowPresenter(androidx.leanback.widget.PlaybackControlsRowPresenter);
-    method public void setFadingEnabled(boolean);
-    method public void setPlaybackRowPresenter(androidx.leanback.widget.PlaybackRowPresenter);
-    method public void updateProgress();
-    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
-    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
-    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
-    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
-    field public static final int ACTION_REWIND = 32; // 0x20
-    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
-    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
-    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
-    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
-    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
-    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
-    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
-    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
-    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
-    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
-  }
-
-  public abstract class PlaybackGlue {
-    ctor public PlaybackGlue(android.content.Context);
-    method public void addPlayerCallback(androidx.leanback.media.PlaybackGlue.PlayerCallback);
-    method public android.content.Context getContext();
-    method public androidx.leanback.media.PlaybackGlueHost getHost();
-    method protected java.util.List<androidx.leanback.media.PlaybackGlue.PlayerCallback> getPlayerCallbacks();
-    method public boolean isPlaying();
-    method public boolean isPrepared();
-    method public void next();
-    method protected void onAttachedToHost(androidx.leanback.media.PlaybackGlueHost);
-    method protected void onDetachedFromHost();
-    method protected void onHostPause();
-    method protected void onHostResume();
-    method protected void onHostStart();
-    method protected void onHostStop();
-    method public void pause();
-    method public void play();
-    method public void playWhenPrepared();
-    method public void previous();
-    method public void removePlayerCallback(androidx.leanback.media.PlaybackGlue.PlayerCallback);
-    method public final void setHost(androidx.leanback.media.PlaybackGlueHost);
-  }
-
-  public static abstract class PlaybackGlue.PlayerCallback {
-    ctor public PlaybackGlue.PlayerCallback();
-    method public void onPlayCompleted(androidx.leanback.media.PlaybackGlue);
-    method public void onPlayStateChanged(androidx.leanback.media.PlaybackGlue);
-    method public void onPreparedStateChanged(androidx.leanback.media.PlaybackGlue);
-  }
-
-  public abstract class PlaybackGlueHost {
-    ctor public PlaybackGlueHost();
-    method public deprecated void fadeOut();
-    method public androidx.leanback.media.PlaybackGlueHost.PlayerCallback getPlayerCallback();
-    method public void hideControlsOverlay(boolean);
-    method public boolean isControlsOverlayAutoHideEnabled();
-    method public boolean isControlsOverlayVisible();
-    method public void notifyPlaybackRowChanged();
-    method public void setControlsOverlayAutoHideEnabled(boolean);
-    method public deprecated void setFadingEnabled(boolean);
-    method public void setHostCallback(androidx.leanback.media.PlaybackGlueHost.HostCallback);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener);
-    method public void setOnKeyInterceptListener(android.view.View.OnKeyListener);
-    method public void setPlaybackRow(androidx.leanback.widget.Row);
-    method public void setPlaybackRowPresenter(androidx.leanback.widget.PlaybackRowPresenter);
-    method public void showControlsOverlay(boolean);
-  }
-
-  public static abstract class PlaybackGlueHost.HostCallback {
-    ctor public PlaybackGlueHost.HostCallback();
-    method public void onHostDestroy();
-    method public void onHostPause();
-    method public void onHostResume();
-    method public void onHostStart();
-    method public void onHostStop();
-  }
-
-  public static class PlaybackGlueHost.PlayerCallback {
-    ctor public PlaybackGlueHost.PlayerCallback();
-    method public void onBufferingStateChanged(boolean);
-    method public void onError(int, java.lang.CharSequence);
-    method public void onVideoSizeChanged(int, int);
-  }
-
-  public class PlaybackTransportControlGlue<T extends androidx.leanback.media.PlayerAdapter> extends androidx.leanback.media.PlaybackBaseControlGlue {
-    ctor public PlaybackTransportControlGlue(android.content.Context, T);
-    method public final androidx.leanback.widget.PlaybackSeekDataProvider getSeekProvider();
-    method public final boolean isSeekEnabled();
-    method public void onActionClicked(androidx.leanback.widget.Action);
-    method protected androidx.leanback.widget.PlaybackRowPresenter onCreateRowPresenter();
-    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
-    method public final void setSeekEnabled(boolean);
-    method public final void setSeekProvider(androidx.leanback.widget.PlaybackSeekDataProvider);
-  }
-
-  public abstract class PlayerAdapter {
-    ctor public PlayerAdapter();
-    method public void fastForward();
-    method public long getBufferedPosition();
-    method public final androidx.leanback.media.PlayerAdapter.Callback getCallback();
-    method public long getCurrentPosition();
-    method public long getDuration();
-    method public long getSupportedActions();
-    method public boolean isPlaying();
-    method public boolean isPrepared();
-    method public void next();
-    method public void onAttachedToHost(androidx.leanback.media.PlaybackGlueHost);
-    method public void onDetachedFromHost();
-    method public abstract void pause();
-    method public abstract void play();
-    method public void previous();
-    method public void rewind();
-    method public void seekTo(long);
-    method public final void setCallback(androidx.leanback.media.PlayerAdapter.Callback);
-    method public void setProgressUpdatingEnabled(boolean);
-    method public void setRepeatAction(int);
-    method public void setShuffleAction(int);
-  }
-
-  public static class PlayerAdapter.Callback {
-    ctor public PlayerAdapter.Callback();
-    method public void onBufferedPositionChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onBufferingStateChanged(androidx.leanback.media.PlayerAdapter, boolean);
-    method public void onCurrentPositionChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onDurationChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onError(androidx.leanback.media.PlayerAdapter, int, java.lang.String);
-    method public void onMetadataChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onPlayCompleted(androidx.leanback.media.PlayerAdapter);
-    method public void onPlayStateChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onPreparedStateChanged(androidx.leanback.media.PlayerAdapter);
-    method public void onVideoSizeChanged(androidx.leanback.media.PlayerAdapter, int, int);
-  }
-
-  public abstract interface SurfaceHolderGlueHost {
-    method public abstract void setSurfaceHolderCallback(android.view.SurfaceHolder.Callback);
-  }
-
-}
-
-package androidx.leanback.system {
-
-  public class Settings {
-    method public boolean getBoolean(java.lang.String);
-    method public static androidx.leanback.system.Settings getInstance(android.content.Context);
-    method public void setBoolean(java.lang.String, boolean);
-    field public static final java.lang.String OUTLINE_CLIPPING_DISABLED = "OUTLINE_CLIPPING_DISABLED";
-    field public static final java.lang.String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
-  }
-
-}
-
-package androidx.leanback.widget {
-
-  public abstract class AbstractDetailsDescriptionPresenter extends androidx.leanback.widget.Presenter {
-    ctor public AbstractDetailsDescriptionPresenter();
-    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, java.lang.Object);
-    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-  }
-
-  public static class AbstractDetailsDescriptionPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
-    method public android.widget.TextView getBody();
-    method public android.widget.TextView getSubtitle();
-    method public android.widget.TextView getTitle();
-  }
-
-  public abstract class AbstractMediaItemPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public AbstractMediaItemPresenter();
-    ctor public AbstractMediaItemPresenter(int);
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method public androidx.leanback.widget.Presenter getActionPresenter();
-    method protected int getMediaPlayState(java.lang.Object);
-    method public int getThemeId();
-    method public boolean hasMediaRowSeparator();
-    method protected abstract void onBindMediaDetails(androidx.leanback.widget.AbstractMediaItemPresenter.ViewHolder, java.lang.Object);
-    method public void onBindMediaPlayState(androidx.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
-    method protected void onBindRowActions(androidx.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
-    method protected void onUnbindMediaDetails(androidx.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
-    method public void onUnbindMediaPlayState(androidx.leanback.widget.AbstractMediaItemPresenter.ViewHolder);
-    method public void setActionPresenter(androidx.leanback.widget.Presenter);
-    method public void setBackgroundColor(int);
-    method public void setHasMediaRowSeparator(boolean);
-    method public void setThemeId(int);
-    field public static final int PLAY_STATE_INITIAL = 0; // 0x0
-    field public static final int PLAY_STATE_PAUSED = 1; // 0x1
-    field public static final int PLAY_STATE_PLAYING = 2; // 0x2
-  }
-
-  public static class AbstractMediaItemPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public AbstractMediaItemPresenter.ViewHolder(android.view.View);
-    method public android.view.ViewGroup getMediaItemActionsContainer();
-    method public android.view.View getMediaItemDetailsView();
-    method public android.widget.TextView getMediaItemDurationView();
-    method public android.widget.TextView getMediaItemNameView();
-    method public android.widget.TextView getMediaItemNumberView();
-    method public android.widget.ViewFlipper getMediaItemNumberViewFlipper();
-    method public android.view.View getMediaItemPausedView();
-    method public android.view.View getMediaItemPlayingView();
-    method public androidx.leanback.widget.MultiActionsProvider.MultiAction[] getMediaItemRowActions();
-    method public android.view.View getMediaItemRowSeparator();
-    method public android.view.View getSelectorView();
-    method public void notifyActionChanged(androidx.leanback.widget.MultiActionsProvider.MultiAction);
-    method public void notifyDetailsChanged();
-    method public void notifyPlayStateChanged();
-    method public void onBindRowActions();
-    method public void setSelectedMediaItemNumberView(int);
-  }
-
-  public abstract class AbstractMediaListHeaderPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public AbstractMediaListHeaderPresenter(android.content.Context, int);
-    ctor public AbstractMediaListHeaderPresenter();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method protected abstract void onBindMediaListHeaderViewHolder(androidx.leanback.widget.AbstractMediaListHeaderPresenter.ViewHolder, java.lang.Object);
-    method public void setBackgroundColor(int);
-  }
-
-  public static class AbstractMediaListHeaderPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public AbstractMediaListHeaderPresenter.ViewHolder(android.view.View);
-    method public android.widget.TextView getHeaderView();
-  }
-
-  public class Action {
-    ctor public Action(long);
-    ctor public Action(long, java.lang.CharSequence);
-    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence);
-    ctor public Action(long, java.lang.CharSequence, java.lang.CharSequence, android.graphics.drawable.Drawable);
-    method public final void addKeyCode(int);
-    method public final android.graphics.drawable.Drawable getIcon();
-    method public final long getId();
-    method public final java.lang.CharSequence getLabel1();
-    method public final java.lang.CharSequence getLabel2();
-    method public final void removeKeyCode(int);
-    method public final boolean respondsToKeyCode(int);
-    method public final void setIcon(android.graphics.drawable.Drawable);
-    method public final void setId(long);
-    method public final void setLabel1(java.lang.CharSequence);
-    method public final void setLabel2(java.lang.CharSequence);
-    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
-  }
-
-  public class ArrayObjectAdapter extends androidx.leanback.widget.ObjectAdapter {
-    ctor public ArrayObjectAdapter(androidx.leanback.widget.PresenterSelector);
-    ctor public ArrayObjectAdapter(androidx.leanback.widget.Presenter);
-    ctor public ArrayObjectAdapter();
-    method public void add(java.lang.Object);
-    method public void add(int, java.lang.Object);
-    method public void addAll(int, java.util.Collection);
-    method public void clear();
-    method public java.lang.Object get(int);
-    method public int indexOf(java.lang.Object);
-    method public void move(int, int);
-    method public void notifyArrayItemRangeChanged(int, int);
-    method public boolean remove(java.lang.Object);
-    method public int removeItems(int, int);
-    method public void replace(int, java.lang.Object);
-    method public void setItems(java.util.List, androidx.leanback.widget.DiffCallback);
-    method public int size();
-    method public <E> java.util.List<E> unmodifiableList();
-  }
-
-  public class BaseCardView extends android.widget.FrameLayout {
-    ctor public BaseCardView(android.content.Context);
-    ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
-    ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
-    method protected androidx.leanback.widget.BaseCardView.LayoutParams generateDefaultLayoutParams();
-    method public androidx.leanback.widget.BaseCardView.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected androidx.leanback.widget.BaseCardView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getCardType();
-    method public deprecated int getExtraVisibility();
-    method public int getInfoVisibility();
-    method public boolean isSelectedAnimationDelayed();
-    method public void setCardType(int);
-    method public deprecated void setExtraVisibility(int);
-    method public void setInfoVisibility(int);
-    method public void setSelectedAnimationDelayed(boolean);
-    field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
-    field public static final int CARD_REGION_VISIBLE_ALWAYS = 0; // 0x0
-    field public static final int CARD_REGION_VISIBLE_SELECTED = 2; // 0x2
-    field public static final int CARD_TYPE_INFO_OVER = 1; // 0x1
-    field public static final int CARD_TYPE_INFO_UNDER = 2; // 0x2
-    field public static final int CARD_TYPE_INFO_UNDER_WITH_EXTRA = 3; // 0x3
-    field public static final int CARD_TYPE_MAIN_ONLY = 0; // 0x0
-  }
-
-  public static class BaseCardView.LayoutParams extends android.widget.FrameLayout.LayoutParams {
-    ctor public BaseCardView.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public BaseCardView.LayoutParams(int, int);
-    ctor public BaseCardView.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public BaseCardView.LayoutParams(androidx.leanback.widget.BaseCardView.LayoutParams);
-    field public static final int VIEW_TYPE_EXTRA = 2; // 0x2
-    field public static final int VIEW_TYPE_INFO = 1; // 0x1
-    field public static final int VIEW_TYPE_MAIN = 0; // 0x0
-    field public int viewType;
-  }
-
-  public abstract class BaseGridView extends androidx.recyclerview.widget.RecyclerView {
-    method public void addOnChildViewHolderSelectedListener(androidx.leanback.widget.OnChildViewHolderSelectedListener);
-    method public void animateIn();
-    method public void animateOut();
-    method public int getChildDrawingOrder(int, int);
-    method public deprecated int getHorizontalMargin();
-    method public int getHorizontalSpacing();
-    method public int getInitialPrefetchItemCount();
-    method public int getItemAlignmentOffset();
-    method public float getItemAlignmentOffsetPercent();
-    method public int getItemAlignmentViewId();
-    method public androidx.leanback.widget.BaseGridView.OnUnhandledKeyListener getOnUnhandledKeyListener();
-    method public final int getSaveChildrenLimitNumber();
-    method public final int getSaveChildrenPolicy();
-    method public int getSelectedPosition();
-    method public deprecated int getVerticalMargin();
-    method public int getVerticalSpacing();
-    method public void getViewSelectedOffsets(android.view.View, int[]);
-    method public int getWindowAlignment();
-    method public int getWindowAlignmentOffset();
-    method public float getWindowAlignmentOffsetPercent();
-    method public boolean hasPreviousViewInSameRow(int);
-    method public boolean isChildLayoutAnimated();
-    method public boolean isFocusDrawingOrderEnabled();
-    method public final boolean isFocusSearchDisabled();
-    method public boolean isItemAlignmentOffsetWithPadding();
-    method public boolean isScrollEnabled();
-    method public boolean isWindowAlignmentPreferKeyLineOverHighEdge();
-    method public boolean isWindowAlignmentPreferKeyLineOverLowEdge();
-    method public boolean onRequestFocusInDescendants(int, android.graphics.Rect);
-    method public void removeOnChildViewHolderSelectedListener(androidx.leanback.widget.OnChildViewHolderSelectedListener);
-    method public void setAnimateChildLayout(boolean);
-    method public void setChildrenVisibility(int);
-    method public void setFocusDrawingOrderEnabled(boolean);
-    method public final void setFocusSearchDisabled(boolean);
-    method public void setGravity(int);
-    method public void setHasOverlappingRendering(boolean);
-    method public deprecated void setHorizontalMargin(int);
-    method public void setHorizontalSpacing(int);
-    method public void setInitialPrefetchItemCount(int);
-    method public void setItemAlignmentOffset(int);
-    method public void setItemAlignmentOffsetPercent(float);
-    method public void setItemAlignmentOffsetWithPadding(boolean);
-    method public void setItemAlignmentViewId(int);
-    method public deprecated void setItemMargin(int);
-    method public void setItemSpacing(int);
-    method public void setLayoutEnabled(boolean);
-    method public void setOnChildLaidOutListener(androidx.leanback.widget.OnChildLaidOutListener);
-    method public void setOnChildSelectedListener(androidx.leanback.widget.OnChildSelectedListener);
-    method public void setOnChildViewHolderSelectedListener(androidx.leanback.widget.OnChildViewHolderSelectedListener);
-    method public void setOnKeyInterceptListener(androidx.leanback.widget.BaseGridView.OnKeyInterceptListener);
-    method public void setOnMotionInterceptListener(androidx.leanback.widget.BaseGridView.OnMotionInterceptListener);
-    method public void setOnTouchInterceptListener(androidx.leanback.widget.BaseGridView.OnTouchInterceptListener);
-    method public void setOnUnhandledKeyListener(androidx.leanback.widget.BaseGridView.OnUnhandledKeyListener);
-    method public void setPruneChild(boolean);
-    method public final void setSaveChildrenLimitNumber(int);
-    method public final void setSaveChildrenPolicy(int);
-    method public void setScrollEnabled(boolean);
-    method public void setSelectedPosition(int);
-    method public void setSelectedPosition(int, int);
-    method public void setSelectedPosition(int, androidx.leanback.widget.ViewHolderTask);
-    method public void setSelectedPositionSmooth(int);
-    method public void setSelectedPositionSmooth(int, androidx.leanback.widget.ViewHolderTask);
-    method public deprecated void setVerticalMargin(int);
-    method public void setVerticalSpacing(int);
-    method public void setWindowAlignment(int);
-    method public void setWindowAlignmentOffset(int);
-    method public void setWindowAlignmentOffsetPercent(float);
-    method public void setWindowAlignmentPreferKeyLineOverHighEdge(boolean);
-    method public void setWindowAlignmentPreferKeyLineOverLowEdge(boolean);
-    field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
-    field public static final int SAVE_ALL_CHILD = 3; // 0x3
-    field public static final int SAVE_LIMITED_CHILD = 2; // 0x2
-    field public static final int SAVE_NO_CHILD = 0; // 0x0
-    field public static final int SAVE_ON_SCREEN_CHILD = 1; // 0x1
-    field public static final int WINDOW_ALIGN_BOTH_EDGE = 3; // 0x3
-    field public static final int WINDOW_ALIGN_HIGH_EDGE = 2; // 0x2
-    field public static final int WINDOW_ALIGN_LOW_EDGE = 1; // 0x1
-    field public static final int WINDOW_ALIGN_NO_EDGE = 0; // 0x0
-    field public static final float WINDOW_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
-  }
-
-  public static abstract interface BaseGridView.OnKeyInterceptListener {
-    method public abstract boolean onInterceptKeyEvent(android.view.KeyEvent);
-  }
-
-  public static abstract interface BaseGridView.OnMotionInterceptListener {
-    method public abstract boolean onInterceptMotionEvent(android.view.MotionEvent);
-  }
-
-  public static abstract interface BaseGridView.OnTouchInterceptListener {
-    method public abstract boolean onInterceptTouchEvent(android.view.MotionEvent);
-  }
-
-  public static abstract interface BaseGridView.OnUnhandledKeyListener {
-    method public abstract boolean onUnhandledKey(android.view.KeyEvent);
-  }
-
-  public abstract interface BaseOnItemViewClickedListener<T> {
-    method public abstract void onItemClicked(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object, androidx.leanback.widget.RowPresenter.ViewHolder, T);
-  }
-
-  public abstract interface BaseOnItemViewSelectedListener<T> {
-    method public abstract void onItemSelected(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object, androidx.leanback.widget.RowPresenter.ViewHolder, T);
-  }
-
-  public class BrowseFrameLayout extends android.widget.FrameLayout {
-    ctor public BrowseFrameLayout(android.content.Context);
-    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet);
-    ctor public BrowseFrameLayout(android.content.Context, android.util.AttributeSet, int);
-    method public androidx.leanback.widget.BrowseFrameLayout.OnChildFocusListener getOnChildFocusListener();
-    method public androidx.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
-    method public void setOnChildFocusListener(androidx.leanback.widget.BrowseFrameLayout.OnChildFocusListener);
-    method public void setOnDispatchKeyListener(android.view.View.OnKeyListener);
-    method public void setOnFocusSearchListener(androidx.leanback.widget.BrowseFrameLayout.OnFocusSearchListener);
-  }
-
-  public static abstract interface BrowseFrameLayout.OnChildFocusListener {
-    method public abstract void onRequestChildFocus(android.view.View, android.view.View);
-    method public abstract boolean onRequestFocusInDescendants(int, android.graphics.Rect);
-  }
-
-  public static abstract interface BrowseFrameLayout.OnFocusSearchListener {
-    method public abstract android.view.View onFocusSearch(android.view.View, int);
-  }
-
-  public final class ClassPresenterSelector extends androidx.leanback.widget.PresenterSelector {
-    ctor public ClassPresenterSelector();
-    method public androidx.leanback.widget.ClassPresenterSelector addClassPresenter(java.lang.Class<?>, androidx.leanback.widget.Presenter);
-    method public androidx.leanback.widget.ClassPresenterSelector addClassPresenterSelector(java.lang.Class<?>, androidx.leanback.widget.PresenterSelector);
-    method public androidx.leanback.widget.Presenter getPresenter(java.lang.Object);
-  }
-
-  public class ControlButtonPresenterSelector extends androidx.leanback.widget.PresenterSelector {
-    ctor public ControlButtonPresenterSelector();
-    method public androidx.leanback.widget.Presenter getPresenter(java.lang.Object);
-    method public androidx.leanback.widget.Presenter getPrimaryPresenter();
-    method public androidx.leanback.widget.Presenter getSecondaryPresenter();
-  }
-
-  public class CursorObjectAdapter extends androidx.leanback.widget.ObjectAdapter {
-    ctor public CursorObjectAdapter(androidx.leanback.widget.PresenterSelector);
-    ctor public CursorObjectAdapter(androidx.leanback.widget.Presenter);
-    ctor public CursorObjectAdapter();
-    method public void changeCursor(android.database.Cursor);
-    method public void close();
-    method public java.lang.Object get(int);
-    method public final android.database.Cursor getCursor();
-    method public final androidx.leanback.database.CursorMapper getMapper();
-    method protected final void invalidateCache(int);
-    method protected final void invalidateCache(int, int);
-    method public boolean isClosed();
-    method protected void onCursorChanged();
-    method protected void onMapperChanged();
-    method public final void setMapper(androidx.leanback.database.CursorMapper);
-    method public int size();
-    method public android.database.Cursor swapCursor(android.database.Cursor);
-  }
-
-  public class DetailsOverviewLogoPresenter extends androidx.leanback.widget.Presenter {
-    ctor public DetailsOverviewLogoPresenter();
-    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.DetailsOverviewRow);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public android.view.View onCreateView(android.view.ViewGroup);
-    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter);
-  }
-
-  public static class DetailsOverviewLogoPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter getParentPresenter();
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder();
-    method public boolean isSizeFromDrawableIntrinsic();
-    method public void setSizeFromDrawableIntrinsic(boolean);
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter mParentPresenter;
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
-  }
-
-  public class DetailsOverviewRow extends androidx.leanback.widget.Row {
-    ctor public DetailsOverviewRow(java.lang.Object);
-    method public final deprecated void addAction(androidx.leanback.widget.Action);
-    method public final deprecated void addAction(int, androidx.leanback.widget.Action);
-    method public androidx.leanback.widget.Action getActionForKeyCode(int);
-    method public final deprecated java.util.List<androidx.leanback.widget.Action> getActions();
-    method public final androidx.leanback.widget.ObjectAdapter getActionsAdapter();
-    method public final android.graphics.drawable.Drawable getImageDrawable();
-    method public final java.lang.Object getItem();
-    method public boolean isImageScaleUpAllowed();
-    method public final deprecated boolean removeAction(androidx.leanback.widget.Action);
-    method public final void setActionsAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
-    method public final void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setImageScaleUpAllowed(boolean);
-    method public final void setItem(java.lang.Object);
-  }
-
-  public static class DetailsOverviewRow.Listener {
-    ctor public DetailsOverviewRow.Listener();
-    method public void onActionsAdapterChanged(androidx.leanback.widget.DetailsOverviewRow);
-    method public void onImageDrawableChanged(androidx.leanback.widget.DetailsOverviewRow);
-    method public void onItemChanged(androidx.leanback.widget.DetailsOverviewRow);
-  }
-
-  public deprecated class DetailsOverviewRowPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public DetailsOverviewRowPresenter(androidx.leanback.widget.Presenter);
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method public int getBackgroundColor();
-    method public androidx.leanback.widget.OnActionClickedListener getOnActionClickedListener();
-    method public boolean isStyleLarge();
-    method public final boolean isUsingDefaultSelectEffect();
-    method public void setBackgroundColor(int);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener);
-    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
-    method public final void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
-    method public void setStyleLarge(boolean);
-  }
-
-  public final class DetailsOverviewRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public DetailsOverviewRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.Presenter);
-    field public final androidx.leanback.widget.Presenter.ViewHolder mDetailsDescriptionViewHolder;
-  }
-
-  public class DetailsParallax extends androidx.leanback.widget.RecyclerViewParallax {
-    ctor public DetailsParallax();
-    method public androidx.leanback.widget.Parallax.IntProperty getOverviewRowBottom();
-    method public androidx.leanback.widget.Parallax.IntProperty getOverviewRowTop();
-  }
-
-  public abstract class DiffCallback<Value> {
-    ctor public DiffCallback();
-    method public abstract boolean areContentsTheSame(Value, Value);
-    method public abstract boolean areItemsTheSame(Value, Value);
-    method public java.lang.Object getChangePayload(Value, Value);
-  }
-
-  public class DividerPresenter extends androidx.leanback.widget.Presenter {
-    ctor public DividerPresenter();
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-  }
-
-  public class DividerRow extends androidx.leanback.widget.Row {
-    ctor public DividerRow();
-    method public final boolean isRenderedAsRowView();
-  }
-
-  public abstract interface FacetProvider {
-    method public abstract java.lang.Object getFacet(java.lang.Class<?>);
-  }
-
-  public abstract interface FacetProviderAdapter {
-    method public abstract androidx.leanback.widget.FacetProvider getFacetProvider(int);
-  }
-
-  public abstract interface FocusHighlight {
-    field public static final int ZOOM_FACTOR_LARGE = 3; // 0x3
-    field public static final int ZOOM_FACTOR_MEDIUM = 2; // 0x2
-    field public static final int ZOOM_FACTOR_NONE = 0; // 0x0
-    field public static final int ZOOM_FACTOR_SMALL = 1; // 0x1
-    field public static final int ZOOM_FACTOR_XSMALL = 4; // 0x4
-  }
-
-  public class FocusHighlightHelper {
-    ctor public FocusHighlightHelper();
-    method public static void setupBrowseItemFocusHighlight(androidx.leanback.widget.ItemBridgeAdapter, int, boolean);
-    method public static deprecated void setupHeaderItemFocusHighlight(androidx.leanback.widget.VerticalGridView);
-    method public static deprecated void setupHeaderItemFocusHighlight(androidx.leanback.widget.VerticalGridView, boolean);
-    method public static void setupHeaderItemFocusHighlight(androidx.leanback.widget.ItemBridgeAdapter);
-    method public static void setupHeaderItemFocusHighlight(androidx.leanback.widget.ItemBridgeAdapter, boolean);
-  }
-
-  public abstract interface FragmentAnimationProvider {
-    method public abstract void onImeAppearing(java.util.List<android.animation.Animator>);
-    method public abstract void onImeDisappearing(java.util.List<android.animation.Animator>);
-  }
-
-  public class FullWidthDetailsOverviewRowPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public FullWidthDetailsOverviewRowPresenter(androidx.leanback.widget.Presenter);
-    ctor public FullWidthDetailsOverviewRowPresenter(androidx.leanback.widget.Presenter, androidx.leanback.widget.DetailsOverviewLogoPresenter);
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method public final int getActionsBackgroundColor();
-    method public final int getAlignmentMode();
-    method public final int getBackgroundColor();
-    method public final int getInitialState();
-    method protected int getLayoutResourceId();
-    method public androidx.leanback.widget.OnActionClickedListener getOnActionClickedListener();
-    method public final boolean isParticipatingEntranceTransition();
-    method public final boolean isUsingDefaultSelectEffect();
-    method public final void notifyOnBindLogo(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
-    method protected void onLayoutLogo(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
-    method protected void onLayoutOverviewFrame(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int, boolean);
-    method protected void onStateChanged(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
-    method public final void setActionsBackgroundColor(int);
-    method public final void setAlignmentMode(int);
-    method public final void setBackgroundColor(int);
-    method public final void setInitialState(int);
-    method public final void setListener(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener);
-    method public final void setParticipatingEntranceTransition(boolean);
-    method public final void setState(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder, int);
-    field public static final int ALIGN_MODE_MIDDLE = 1; // 0x1
-    field public static final int ALIGN_MODE_START = 0; // 0x0
-    field public static final int STATE_FULL = 1; // 0x1
-    field public static final int STATE_HALF = 0; // 0x0
-    field public static final int STATE_SMALL = 2; // 0x2
-    field protected int mInitialState;
-  }
-
-  public static abstract class FullWidthDetailsOverviewRowPresenter.Listener {
-    ctor public FullWidthDetailsOverviewRowPresenter.Listener();
-    method public void onBindLogo(androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder);
-  }
-
-  public class FullWidthDetailsOverviewRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.Presenter, androidx.leanback.widget.DetailsOverviewLogoPresenter);
-    method protected androidx.leanback.widget.DetailsOverviewRow.Listener createRowListener();
-    method public final android.view.ViewGroup getActionsRow();
-    method public final android.view.ViewGroup getDetailsDescriptionFrame();
-    method public final androidx.leanback.widget.Presenter.ViewHolder getDetailsDescriptionViewHolder();
-    method public final androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder getLogoViewHolder();
-    method public final android.view.ViewGroup getOverviewView();
-    method public final int getState();
-    field protected final androidx.leanback.widget.DetailsOverviewRow.Listener mRowListener;
-  }
-
-  public class FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener extends androidx.leanback.widget.DetailsOverviewRow.Listener {
-    ctor public FullWidthDetailsOverviewRowPresenter.ViewHolder.DetailsOverviewRowListener();
-  }
-
-  public class FullWidthDetailsOverviewSharedElementHelper extends androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.Listener {
-    ctor public FullWidthDetailsOverviewSharedElementHelper();
-    method public boolean getAutoStartSharedElementTransition();
-    method public void setAutoStartSharedElementTransition(boolean);
-    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String);
-    method public void setSharedElementEnterTransition(android.app.Activity, java.lang.String, long);
-    method public void startPostponedEnterTransition();
-  }
-
-  public class GuidanceStylist implements androidx.leanback.widget.FragmentAnimationProvider {
-    ctor public GuidanceStylist();
-    method public android.widget.TextView getBreadcrumbView();
-    method public android.widget.TextView getDescriptionView();
-    method public android.widget.ImageView getIconView();
-    method public android.widget.TextView getTitleView();
-    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, androidx.leanback.widget.GuidanceStylist.Guidance);
-    method public void onDestroyView();
-    method public void onImeAppearing(java.util.List<android.animation.Animator>);
-    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
-    method public int onProvideLayoutId();
-  }
-
-  public static class GuidanceStylist.Guidance {
-    ctor public GuidanceStylist.Guidance(java.lang.String, java.lang.String, java.lang.String, android.graphics.drawable.Drawable);
-    method public java.lang.String getBreadcrumb();
-    method public java.lang.String getDescription();
-    method public android.graphics.drawable.Drawable getIconDrawable();
-    method public java.lang.String getTitle();
-  }
-
-  public class GuidedAction extends androidx.leanback.widget.Action {
-    ctor protected GuidedAction();
-    method public int getCheckSetId();
-    method public java.lang.CharSequence getDescription();
-    method public int getDescriptionEditInputType();
-    method public int getDescriptionInputType();
-    method public java.lang.CharSequence getEditDescription();
-    method public int getEditInputType();
-    method public java.lang.CharSequence getEditTitle();
-    method public int getInputType();
-    method public android.content.Intent getIntent();
-    method public java.util.List<androidx.leanback.widget.GuidedAction> getSubActions();
-    method public java.lang.CharSequence getTitle();
-    method public boolean hasEditableActivatorView();
-    method public boolean hasMultilineDescription();
-    method public boolean hasNext();
-    method public boolean hasSubActions();
-    method public boolean hasTextEditable();
-    method public boolean infoOnly();
-    method public final boolean isAutoSaveRestoreEnabled();
-    method public boolean isChecked();
-    method public boolean isDescriptionEditable();
-    method public boolean isEditTitleUsed();
-    method public boolean isEditable();
-    method public boolean isEnabled();
-    method public boolean isFocusable();
-    method public void onRestoreInstanceState(android.os.Bundle, java.lang.String);
-    method public void onSaveInstanceState(android.os.Bundle, java.lang.String);
-    method public void setChecked(boolean);
-    method public void setDescription(java.lang.CharSequence);
-    method public void setEditDescription(java.lang.CharSequence);
-    method public void setEditTitle(java.lang.CharSequence);
-    method public void setEnabled(boolean);
-    method public void setFocusable(boolean);
-    method public void setIntent(android.content.Intent);
-    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public void setTitle(java.lang.CharSequence);
-    field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
-    field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
-    field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
-    field public static final long ACTION_ID_FINISH = -6L; // 0xfffffffffffffffaL
-    field public static final long ACTION_ID_NEXT = -2L; // 0xfffffffffffffffeL
-    field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
-    field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
-    field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
-    field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
-    field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
-    field public static final int NO_CHECK_SET = 0; // 0x0
-  }
-
-  public static class GuidedAction.Builder extends androidx.leanback.widget.GuidedAction.BuilderBase {
-    ctor public deprecated GuidedAction.Builder();
-    ctor public GuidedAction.Builder(android.content.Context);
-    method public androidx.leanback.widget.GuidedAction build();
-  }
-
-  public static abstract class GuidedAction.BuilderBase<B extends androidx.leanback.widget.GuidedAction.BuilderBase> {
-    ctor public GuidedAction.BuilderBase(android.content.Context);
-    method protected final void applyValues(androidx.leanback.widget.GuidedAction);
-    method public B autoSaveRestoreEnabled(boolean);
-    method public B checkSetId(int);
-    method public B checked(boolean);
-    method public B clickAction(long);
-    method public B description(java.lang.CharSequence);
-    method public B description(int);
-    method public B descriptionEditInputType(int);
-    method public B descriptionEditable(boolean);
-    method public B descriptionInputType(int);
-    method public B editDescription(java.lang.CharSequence);
-    method public B editDescription(int);
-    method public B editInputType(int);
-    method public B editTitle(java.lang.CharSequence);
-    method public B editTitle(int);
-    method public B editable(boolean);
-    method public B enabled(boolean);
-    method public B focusable(boolean);
-    method public android.content.Context getContext();
-    method public B hasEditableActivatorView(boolean);
-    method public B hasNext(boolean);
-    method public B icon(android.graphics.drawable.Drawable);
-    method public B icon(int);
-    method public deprecated B iconResourceId(int, android.content.Context);
-    method public B id(long);
-    method public B infoOnly(boolean);
-    method public B inputType(int);
-    method public B intent(android.content.Intent);
-    method public B multilineDescription(boolean);
-    method public B subActions(java.util.List<androidx.leanback.widget.GuidedAction>);
-    method public B title(java.lang.CharSequence);
-    method public B title(int);
-  }
-
-  public class GuidedActionDiffCallback extends androidx.leanback.widget.DiffCallback {
-    ctor public GuidedActionDiffCallback();
-    method public boolean areContentsTheSame(androidx.leanback.widget.GuidedAction, androidx.leanback.widget.GuidedAction);
-    method public boolean areItemsTheSame(androidx.leanback.widget.GuidedAction, androidx.leanback.widget.GuidedAction);
-    method public static androidx.leanback.widget.GuidedActionDiffCallback getInstance();
-  }
-
-  public class GuidedActionEditText extends android.widget.EditText implements androidx.leanback.widget.ImeKeyMonitor {
-    ctor public GuidedActionEditText(android.content.Context);
-    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet);
-    ctor public GuidedActionEditText(android.content.Context, android.util.AttributeSet, int);
-    method public void setImeKeyListener(androidx.leanback.widget.ImeKeyMonitor.ImeKeyListener);
-  }
-
-  public class GuidedActionsStylist implements androidx.leanback.widget.FragmentAnimationProvider {
-    ctor public GuidedActionsStylist();
-    method public void collapseAction(boolean);
-    method public void expandAction(androidx.leanback.widget.GuidedAction, boolean);
-    method public androidx.leanback.widget.VerticalGridView getActionsGridView();
-    method public androidx.leanback.widget.GuidedAction getExpandedAction();
-    method public int getItemViewType(androidx.leanback.widget.GuidedAction);
-    method public androidx.leanback.widget.VerticalGridView getSubActionsGridView();
-    method public final boolean isBackKeyToCollapseActivatorView();
-    method public final boolean isBackKeyToCollapseSubActions();
-    method public boolean isButtonActions();
-    method public boolean isExpandTransitionSupported();
-    method public boolean isExpanded();
-    method public boolean isInExpandTransition();
-    method public boolean isSubActionsExpanded();
-    method public void onAnimateItemChecked(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
-    method public void onAnimateItemFocused(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
-    method public void onAnimateItemPressed(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
-    method public void onAnimateItemPressedCancelled(androidx.leanback.widget.GuidedActionsStylist.ViewHolder);
-    method public void onBindActivatorView(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public void onBindCheckMarkView(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public void onBindChevronView(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public void onBindViewHolder(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
-    method public androidx.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public androidx.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
-    method public void onDestroyView();
-    method protected deprecated void onEditingModeChange(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction, boolean);
-    method protected void onEditingModeChange(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, boolean, boolean);
-    method public void onImeAppearing(java.util.List<android.animation.Animator>);
-    method public void onImeDisappearing(java.util.List<android.animation.Animator>);
-    method public int onProvideItemLayoutId();
-    method public int onProvideItemLayoutId(int);
-    method public int onProvideLayoutId();
-    method public boolean onUpdateActivatorView(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public void onUpdateExpandedViewHolder(androidx.leanback.widget.GuidedActionsStylist.ViewHolder);
-    method public void openInEditMode(androidx.leanback.widget.GuidedAction);
-    method public void setAsButtonActions();
-    method public final void setBackKeyToCollapseActivatorView(boolean);
-    method public final void setBackKeyToCollapseSubActions(boolean);
-    method public deprecated void setEditingMode(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction, boolean);
-    method public deprecated void setExpandedViewHolder(androidx.leanback.widget.GuidedActionsStylist.ViewHolder);
-    method protected void setupImeOptions(androidx.leanback.widget.GuidedActionsStylist.ViewHolder, androidx.leanback.widget.GuidedAction);
-    method public deprecated void startExpandedTransition(androidx.leanback.widget.GuidedActionsStylist.ViewHolder);
-    field public static final int VIEW_TYPE_DATE_PICKER = 1; // 0x1
-    field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
-  }
-
-  public static class GuidedActionsStylist.ViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder implements androidx.leanback.widget.FacetProvider {
-    ctor public GuidedActionsStylist.ViewHolder(android.view.View);
-    ctor public GuidedActionsStylist.ViewHolder(android.view.View, boolean);
-    method public androidx.leanback.widget.GuidedAction getAction();
-    method public android.widget.ImageView getCheckmarkView();
-    method public android.widget.ImageView getChevronView();
-    method public android.view.View getContentView();
-    method public android.widget.TextView getDescriptionView();
-    method public android.widget.EditText getEditableDescriptionView();
-    method public android.widget.EditText getEditableTitleView();
-    method public android.view.View getEditingView();
-    method public java.lang.Object getFacet(java.lang.Class<?>);
-    method public android.widget.ImageView getIconView();
-    method public android.widget.TextView getTitleView();
-    method public boolean isInEditing();
-    method public boolean isInEditingActivatorView();
-    method public boolean isInEditingDescription();
-    method public boolean isInEditingText();
-    method public boolean isInEditingTitle();
-    method public boolean isSubAction();
-  }
-
-  public class GuidedDatePickerAction extends androidx.leanback.widget.GuidedAction {
-    ctor public GuidedDatePickerAction();
-    method public long getDate();
-    method public java.lang.String getDatePickerFormat();
-    method public long getMaxDate();
-    method public long getMinDate();
-    method public void setDate(long);
-  }
-
-  public static final class GuidedDatePickerAction.Builder extends androidx.leanback.widget.GuidedDatePickerAction.BuilderBase {
-    ctor public GuidedDatePickerAction.Builder(android.content.Context);
-    method public androidx.leanback.widget.GuidedDatePickerAction build();
-  }
-
-  public static abstract class GuidedDatePickerAction.BuilderBase<B extends androidx.leanback.widget.GuidedDatePickerAction.BuilderBase> extends androidx.leanback.widget.GuidedAction.BuilderBase {
-    ctor public GuidedDatePickerAction.BuilderBase(android.content.Context);
-    method protected final void applyDatePickerValues(androidx.leanback.widget.GuidedDatePickerAction);
-    method public B date(long);
-    method public B datePickerFormat(java.lang.String);
-    method public B maxDate(long);
-    method public B minDate(long);
-  }
-
-  public class HeaderItem {
-    ctor public HeaderItem(long, java.lang.String);
-    ctor public HeaderItem(java.lang.String);
-    method public java.lang.CharSequence getContentDescription();
-    method public java.lang.CharSequence getDescription();
-    method public final long getId();
-    method public final java.lang.String getName();
-    method public void setContentDescription(java.lang.CharSequence);
-    method public void setDescription(java.lang.CharSequence);
-  }
-
-  public class HorizontalGridView extends androidx.leanback.widget.BaseGridView {
-    ctor public HorizontalGridView(android.content.Context);
-    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet);
-    ctor public HorizontalGridView(android.content.Context, android.util.AttributeSet, int);
-    method public final boolean getFadingLeftEdge();
-    method public final int getFadingLeftEdgeLength();
-    method public final int getFadingLeftEdgeOffset();
-    method public final boolean getFadingRightEdge();
-    method public final int getFadingRightEdgeLength();
-    method public final int getFadingRightEdgeOffset();
-    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
-    method public final void setFadingLeftEdge(boolean);
-    method public final void setFadingLeftEdgeLength(int);
-    method public final void setFadingLeftEdgeOffset(int);
-    method public final void setFadingRightEdge(boolean);
-    method public final void setFadingRightEdgeLength(int);
-    method public final void setFadingRightEdgeOffset(int);
-    method public void setNumRows(int);
-    method public void setRowHeight(int);
-  }
-
-  public final class HorizontalHoverCardSwitcher extends androidx.leanback.widget.PresenterSwitcher {
-    ctor public HorizontalHoverCardSwitcher();
-    method protected void insertView(android.view.View);
-    method public void select(androidx.leanback.widget.HorizontalGridView, android.view.View, java.lang.Object);
-  }
-
-  public class ImageCardView extends androidx.leanback.widget.BaseCardView {
-    ctor public deprecated ImageCardView(android.content.Context, int);
-    ctor public ImageCardView(android.content.Context, android.util.AttributeSet, int);
-    ctor public ImageCardView(android.content.Context);
-    ctor public ImageCardView(android.content.Context, android.util.AttributeSet);
-    method public android.graphics.drawable.Drawable getBadgeImage();
-    method public java.lang.CharSequence getContentText();
-    method public android.graphics.drawable.Drawable getInfoAreaBackground();
-    method public android.graphics.drawable.Drawable getMainImage();
-    method public final android.widget.ImageView getMainImageView();
-    method public java.lang.CharSequence getTitleText();
-    method public void setBadgeImage(android.graphics.drawable.Drawable);
-    method public void setContentText(java.lang.CharSequence);
-    method public void setInfoAreaBackground(android.graphics.drawable.Drawable);
-    method public void setInfoAreaBackgroundColor(int);
-    method public void setMainImage(android.graphics.drawable.Drawable);
-    method public void setMainImage(android.graphics.drawable.Drawable, boolean);
-    method public void setMainImageAdjustViewBounds(boolean);
-    method public void setMainImageDimensions(int, int);
-    method public void setMainImageScaleType(android.widget.ImageView.ScaleType);
-    method public void setTitleText(java.lang.CharSequence);
-    field public static final int CARD_TYPE_FLAG_CONTENT = 2; // 0x2
-    field public static final int CARD_TYPE_FLAG_ICON_LEFT = 8; // 0x8
-    field public static final int CARD_TYPE_FLAG_ICON_RIGHT = 4; // 0x4
-    field public static final int CARD_TYPE_FLAG_IMAGE_ONLY = 0; // 0x0
-    field public static final int CARD_TYPE_FLAG_TITLE = 1; // 0x1
-  }
-
-  public abstract interface ImeKeyMonitor {
-    method public abstract void setImeKeyListener(androidx.leanback.widget.ImeKeyMonitor.ImeKeyListener);
-  }
-
-  public static abstract interface ImeKeyMonitor.ImeKeyListener {
-    method public abstract boolean onKeyPreIme(android.widget.EditText, int, android.view.KeyEvent);
-  }
-
-  public final class ItemAlignmentFacet {
-    ctor public ItemAlignmentFacet();
-    method public androidx.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[] getAlignmentDefs();
-    method public boolean isMultiAlignment();
-    method public void setAlignmentDefs(androidx.leanback.widget.ItemAlignmentFacet.ItemAlignmentDef[]);
-    field public static final float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1.0f;
-  }
-
-  public static class ItemAlignmentFacet.ItemAlignmentDef {
-    ctor public ItemAlignmentFacet.ItemAlignmentDef();
-    method public final int getItemAlignmentFocusViewId();
-    method public final int getItemAlignmentOffset();
-    method public final float getItemAlignmentOffsetPercent();
-    method public final int getItemAlignmentViewId();
-    method public boolean isAlignedToTextViewBaseLine();
-    method public final boolean isItemAlignmentOffsetWithPadding();
-    method public final void setAlignedToTextViewBaseline(boolean);
-    method public final void setItemAlignmentFocusViewId(int);
-    method public final void setItemAlignmentOffset(int);
-    method public final void setItemAlignmentOffsetPercent(float);
-    method public final void setItemAlignmentOffsetWithPadding(boolean);
-    method public final void setItemAlignmentViewId(int);
-  }
-
-  public class ItemBridgeAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter implements androidx.leanback.widget.FacetProviderAdapter {
-    ctor public ItemBridgeAdapter(androidx.leanback.widget.ObjectAdapter, androidx.leanback.widget.PresenterSelector);
-    ctor public ItemBridgeAdapter(androidx.leanback.widget.ObjectAdapter);
-    ctor public ItemBridgeAdapter();
-    method public void clear();
-    method public androidx.leanback.widget.FacetProvider getFacetProvider(int);
-    method public int getItemCount();
-    method public java.util.ArrayList<androidx.leanback.widget.Presenter> getPresenterMapper();
-    method public androidx.leanback.widget.ItemBridgeAdapter.Wrapper getWrapper();
-    method protected void onAddPresenter(androidx.leanback.widget.Presenter, int);
-    method protected void onAttachedToWindow(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method protected void onBind(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public final void onBindViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
-    method public final void onBindViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, java.util.List);
-    method protected void onCreate(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public final androidx.recyclerview.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
-    method protected void onDetachedFromWindow(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method protected void onUnbind(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public final void onViewAttachedToWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void onViewDetachedFromWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public void setAdapterListener(androidx.leanback.widget.ItemBridgeAdapter.AdapterListener);
-    method public void setPresenter(androidx.leanback.widget.PresenterSelector);
-    method public void setPresenterMapper(java.util.ArrayList<androidx.leanback.widget.Presenter>);
-    method public void setWrapper(androidx.leanback.widget.ItemBridgeAdapter.Wrapper);
-  }
-
-  public static class ItemBridgeAdapter.AdapterListener {
-    ctor public ItemBridgeAdapter.AdapterListener();
-    method public void onAddPresenter(androidx.leanback.widget.Presenter, int);
-    method public void onAttachedToWindow(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public void onBind(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public void onBind(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder, java.util.List);
-    method public void onCreate(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public void onDetachedFromWindow(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-    method public void onUnbind(androidx.leanback.widget.ItemBridgeAdapter.ViewHolder);
-  }
-
-  public class ItemBridgeAdapter.ViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder implements androidx.leanback.widget.FacetProvider {
-    method public final java.lang.Object getExtraObject();
-    method public java.lang.Object getFacet(java.lang.Class<?>);
-    method public final java.lang.Object getItem();
-    method public final androidx.leanback.widget.Presenter getPresenter();
-    method public final androidx.leanback.widget.Presenter.ViewHolder getViewHolder();
-    method public void setExtraObject(java.lang.Object);
-  }
-
-  public static abstract class ItemBridgeAdapter.Wrapper {
-    ctor public ItemBridgeAdapter.Wrapper();
-    method public abstract android.view.View createWrapper(android.view.View);
-    method public abstract void wrap(android.view.View, android.view.View);
-  }
-
-  public class ItemBridgeAdapterShadowOverlayWrapper extends androidx.leanback.widget.ItemBridgeAdapter.Wrapper {
-    ctor public ItemBridgeAdapterShadowOverlayWrapper(androidx.leanback.widget.ShadowOverlayHelper);
-    method public android.view.View createWrapper(android.view.View);
-    method public void wrap(android.view.View, android.view.View);
-  }
-
-  public class ListRow extends androidx.leanback.widget.Row {
-    ctor public ListRow(androidx.leanback.widget.HeaderItem, androidx.leanback.widget.ObjectAdapter);
-    ctor public ListRow(long, androidx.leanback.widget.HeaderItem, androidx.leanback.widget.ObjectAdapter);
-    ctor public ListRow(androidx.leanback.widget.ObjectAdapter);
-    method public final androidx.leanback.widget.ObjectAdapter getAdapter();
-    method public java.lang.CharSequence getContentDescription();
-    method public void setContentDescription(java.lang.CharSequence);
-  }
-
-  public final class ListRowHoverCardView extends android.widget.LinearLayout {
-    ctor public ListRowHoverCardView(android.content.Context);
-    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet);
-    ctor public ListRowHoverCardView(android.content.Context, android.util.AttributeSet, int);
-    method public java.lang.CharSequence getDescription();
-    method public java.lang.CharSequence getTitle();
-    method public void setDescription(java.lang.CharSequence);
-    method public void setTitle(java.lang.CharSequence);
-  }
-
-  public class ListRowPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public ListRowPresenter();
-    ctor public ListRowPresenter(int);
-    ctor public ListRowPresenter(int, boolean);
-    method protected void applySelectLevelToChild(androidx.leanback.widget.ListRowPresenter.ViewHolder, android.view.View);
-    method public final boolean areChildRoundedCornersEnabled();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method protected androidx.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
-    method public final void enableChildRoundedCorners(boolean);
-    method public int getExpandedRowHeight();
-    method public final int getFocusZoomFactor();
-    method public final androidx.leanback.widget.PresenterSelector getHoverCardPresenterSelector();
-    method public int getRecycledPoolSize(androidx.leanback.widget.Presenter);
-    method public int getRowHeight();
-    method public final boolean getShadowEnabled();
-    method public final deprecated int getZoomFactor();
-    method public final boolean isFocusDimmerUsed();
-    method public final boolean isKeepChildForeground();
-    method public boolean isUsingDefaultListSelectEffect();
-    method public final boolean isUsingDefaultSelectEffect();
-    method public boolean isUsingDefaultShadow();
-    method public boolean isUsingOutlineClipping(android.content.Context);
-    method public boolean isUsingZOrder(android.content.Context);
-    method public void setExpandedRowHeight(int);
-    method public final void setHoverCardPresenterSelector(androidx.leanback.widget.PresenterSelector);
-    method public final void setKeepChildForeground(boolean);
-    method public void setNumRows(int);
-    method public void setRecycledPoolSize(androidx.leanback.widget.Presenter, int);
-    method public void setRowHeight(int);
-    method public final void setShadowEnabled(boolean);
-  }
-
-  public static class ListRowPresenter.SelectItemViewHolderTask extends androidx.leanback.widget.Presenter.ViewHolderTask {
-    ctor public ListRowPresenter.SelectItemViewHolderTask(int);
-    method public int getItemPosition();
-    method public androidx.leanback.widget.Presenter.ViewHolderTask getItemTask();
-    method public boolean isSmoothScroll();
-    method public void setItemPosition(int);
-    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask);
-    method public void setSmoothScroll(boolean);
-  }
-
-  public static class ListRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public ListRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.HorizontalGridView, androidx.leanback.widget.ListRowPresenter);
-    method public final androidx.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
-    method public final androidx.leanback.widget.HorizontalGridView getGridView();
-    method public androidx.leanback.widget.Presenter.ViewHolder getItemViewHolder(int);
-    method public final androidx.leanback.widget.ListRowPresenter getListRowPresenter();
-    method public int getSelectedPosition();
-  }
-
-  public final class ListRowView extends android.widget.LinearLayout {
-    ctor public ListRowView(android.content.Context);
-    ctor public ListRowView(android.content.Context, android.util.AttributeSet);
-    ctor public ListRowView(android.content.Context, android.util.AttributeSet, int);
-    method public androidx.leanback.widget.HorizontalGridView getGridView();
-  }
-
-  public abstract interface MultiActionsProvider {
-    method public abstract androidx.leanback.widget.MultiActionsProvider.MultiAction[] getActions();
-  }
-
-  public static class MultiActionsProvider.MultiAction {
-    ctor public MultiActionsProvider.MultiAction(long);
-    method public android.graphics.drawable.Drawable getCurrentDrawable();
-    method public android.graphics.drawable.Drawable[] getDrawables();
-    method public long getId();
-    method public int getIndex();
-    method public void incrementIndex();
-    method public void setDrawables(android.graphics.drawable.Drawable[]);
-    method public void setIndex(int);
-  }
-
-  public abstract class ObjectAdapter {
-    ctor public ObjectAdapter(androidx.leanback.widget.PresenterSelector);
-    ctor public ObjectAdapter(androidx.leanback.widget.Presenter);
-    ctor public ObjectAdapter();
-    method public abstract java.lang.Object get(int);
-    method public long getId(int);
-    method public final androidx.leanback.widget.Presenter getPresenter(java.lang.Object);
-    method public final androidx.leanback.widget.PresenterSelector getPresenterSelector();
-    method public final boolean hasStableIds();
-    method public boolean isImmediateNotifySupported();
-    method protected final void notifyChanged();
-    method protected final void notifyItemMoved(int, int);
-    method public final void notifyItemRangeChanged(int, int);
-    method public final void notifyItemRangeChanged(int, int, java.lang.Object);
-    method protected final void notifyItemRangeInserted(int, int);
-    method protected final void notifyItemRangeRemoved(int, int);
-    method protected void onHasStableIdsChanged();
-    method protected void onPresenterSelectorChanged();
-    method public final void registerObserver(androidx.leanback.widget.ObjectAdapter.DataObserver);
-    method public final void setHasStableIds(boolean);
-    method public final void setPresenterSelector(androidx.leanback.widget.PresenterSelector);
-    method public abstract int size();
-    method public final void unregisterAllObservers();
-    method public final void unregisterObserver(androidx.leanback.widget.ObjectAdapter.DataObserver);
-    field public static final int NO_ID = -1; // 0xffffffff
-  }
-
-  public static abstract class ObjectAdapter.DataObserver {
-    ctor public ObjectAdapter.DataObserver();
-    method public void onChanged();
-    method public void onItemMoved(int, int);
-    method public void onItemRangeChanged(int, int);
-    method public void onItemRangeChanged(int, int, java.lang.Object);
-    method public void onItemRangeInserted(int, int);
-    method public void onItemRangeRemoved(int, int);
-  }
-
-  public abstract interface OnActionClickedListener {
-    method public abstract void onActionClicked(androidx.leanback.widget.Action);
-  }
-
-  public abstract interface OnChildLaidOutListener {
-    method public abstract void onChildLaidOut(android.view.ViewGroup, android.view.View, int, long);
-  }
-
-  public abstract deprecated interface OnChildSelectedListener {
-    method public abstract void onChildSelected(android.view.ViewGroup, android.view.View, int, long);
-  }
-
-  public abstract class OnChildViewHolderSelectedListener {
-    ctor public OnChildViewHolderSelectedListener();
-    method public void onChildViewHolderSelected(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int);
-    method public void onChildViewHolderSelectedAndPositioned(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int);
-  }
-
-  public abstract interface OnItemViewClickedListener implements androidx.leanback.widget.BaseOnItemViewClickedListener {
-  }
-
-  public abstract interface OnItemViewSelectedListener implements androidx.leanback.widget.BaseOnItemViewSelectedListener {
-  }
-
-  public class PageRow extends androidx.leanback.widget.Row {
-    ctor public PageRow(androidx.leanback.widget.HeaderItem);
-    method public final boolean isRenderedAsRowView();
-  }
-
-  public abstract class Parallax<PropertyT extends android.util.Property> {
-    ctor public Parallax();
-    method public androidx.leanback.widget.ParallaxEffect addEffect(androidx.leanback.widget.Parallax.PropertyMarkerValue...);
-    method public final PropertyT addProperty(java.lang.String);
-    method public abstract PropertyT createProperty(java.lang.String, int);
-    method public java.util.List<androidx.leanback.widget.ParallaxEffect> getEffects();
-    method public abstract float getMaxValue();
-    method public final java.util.List<PropertyT> getProperties();
-    method public void removeAllEffects();
-    method public void removeEffect(androidx.leanback.widget.ParallaxEffect);
-    method public void updateValues();
-  }
-
-  public static class Parallax.FloatProperty extends android.util.Property {
-    ctor public Parallax.FloatProperty(java.lang.String, int);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue at(float, float);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(float);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atMax();
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atMin();
-    method public final java.lang.Float get(androidx.leanback.widget.Parallax);
-    method public final int getIndex();
-    method public final float getValue(androidx.leanback.widget.Parallax);
-    method public final void set(androidx.leanback.widget.Parallax, java.lang.Float);
-    method public final void setValue(androidx.leanback.widget.Parallax, float);
-    field public static final float UNKNOWN_AFTER = 3.4028235E38f;
-    field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
-  }
-
-  public static class Parallax.IntProperty extends android.util.Property {
-    ctor public Parallax.IntProperty(java.lang.String, int);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue at(int, float);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atAbsolute(int);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atFraction(float);
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atMax();
-    method public final androidx.leanback.widget.Parallax.PropertyMarkerValue atMin();
-    method public final java.lang.Integer get(androidx.leanback.widget.Parallax);
-    method public final int getIndex();
-    method public final int getValue(androidx.leanback.widget.Parallax);
-    method public final void set(androidx.leanback.widget.Parallax, java.lang.Integer);
-    method public final void setValue(androidx.leanback.widget.Parallax, int);
-    field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
-    field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
-  }
-
-  public static class Parallax.PropertyMarkerValue<PropertyT> {
-    ctor public Parallax.PropertyMarkerValue(PropertyT);
-    method public PropertyT getProperty();
-  }
-
-  public abstract class ParallaxEffect {
-    method public final void addTarget(androidx.leanback.widget.ParallaxTarget);
-    method public final java.util.List<androidx.leanback.widget.Parallax.PropertyMarkerValue> getPropertyRanges();
-    method public final java.util.List<androidx.leanback.widget.ParallaxTarget> getTargets();
-    method public final void performMapping(androidx.leanback.widget.Parallax);
-    method public final void removeTarget(androidx.leanback.widget.ParallaxTarget);
-    method public final void setPropertyRanges(androidx.leanback.widget.Parallax.PropertyMarkerValue...);
-    method public final androidx.leanback.widget.ParallaxEffect target(androidx.leanback.widget.ParallaxTarget);
-    method public final androidx.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
-    method public final <T, V extends java.lang.Number> androidx.leanback.widget.ParallaxEffect target(T, android.util.Property<T, V>);
-  }
-
-  public abstract class ParallaxTarget {
-    ctor public ParallaxTarget();
-    method public void directUpdate(java.lang.Number);
-    method public boolean isDirectMapping();
-    method public void update(float);
-  }
-
-  public static final class ParallaxTarget.DirectPropertyTarget<T, V extends java.lang.Number> extends androidx.leanback.widget.ParallaxTarget {
-    ctor public ParallaxTarget.DirectPropertyTarget(java.lang.Object, android.util.Property<T, V>);
-  }
-
-  public static final class ParallaxTarget.PropertyValuesHolderTarget extends androidx.leanback.widget.ParallaxTarget {
-    ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
-  }
-
-  public class PlaybackControlsRow extends androidx.leanback.widget.Row {
-    ctor public PlaybackControlsRow(java.lang.Object);
-    ctor public PlaybackControlsRow();
-    method public androidx.leanback.widget.Action getActionForKeyCode(int);
-    method public androidx.leanback.widget.Action getActionForKeyCode(androidx.leanback.widget.ObjectAdapter, int);
-    method public long getBufferedPosition();
-    method public deprecated int getBufferedProgress();
-    method public deprecated long getBufferedProgressLong();
-    method public long getCurrentPosition();
-    method public deprecated int getCurrentTime();
-    method public deprecated long getCurrentTimeLong();
-    method public long getDuration();
-    method public final android.graphics.drawable.Drawable getImageDrawable();
-    method public final java.lang.Object getItem();
-    method public final androidx.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
-    method public final androidx.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
-    method public deprecated int getTotalTime();
-    method public deprecated long getTotalTimeLong();
-    method public void setBufferedPosition(long);
-    method public deprecated void setBufferedProgress(int);
-    method public deprecated void setBufferedProgressLong(long);
-    method public void setCurrentPosition(long);
-    method public deprecated void setCurrentTime(int);
-    method public deprecated void setCurrentTimeLong(long);
-    method public void setDuration(long);
-    method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
-    method public final void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setOnPlaybackProgressChangedListener(androidx.leanback.widget.PlaybackControlsRow.OnPlaybackProgressCallback);
-    method public final void setPrimaryActionsAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public final void setSecondaryActionsAdapter(androidx.leanback.widget.ObjectAdapter);
-    method public deprecated void setTotalTime(int);
-    method public deprecated void setTotalTimeLong(long);
-  }
-
-  public static class PlaybackControlsRow.ClosedCaptioningAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context);
-    ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
-    field public static final int INDEX_OFF = 0; // 0x0
-    field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
-  }
-
-  public static class PlaybackControlsRow.FastForwardAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context);
-    ctor public PlaybackControlsRow.FastForwardAction(android.content.Context, int);
-  }
-
-  public static class PlaybackControlsRow.HighQualityAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context);
-    ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
-    field public static final int INDEX_OFF = 0; // 0x0
-    field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
-  }
-
-  public static class PlaybackControlsRow.MoreActions extends androidx.leanback.widget.Action {
-    ctor public PlaybackControlsRow.MoreActions(android.content.Context);
-  }
-
-  public static abstract class PlaybackControlsRow.MultiAction extends androidx.leanback.widget.Action {
-    ctor public PlaybackControlsRow.MultiAction(int);
-    method public int getActionCount();
-    method public android.graphics.drawable.Drawable getDrawable(int);
-    method public int getIndex();
-    method public java.lang.String getLabel(int);
-    method public java.lang.String getSecondaryLabel(int);
-    method public void nextIndex();
-    method public void setDrawables(android.graphics.drawable.Drawable[]);
-    method public void setIndex(int);
-    method public void setLabels(java.lang.String[]);
-    method public void setSecondaryLabels(java.lang.String[]);
-  }
-
-  public static class PlaybackControlsRow.OnPlaybackProgressCallback {
-    ctor public PlaybackControlsRow.OnPlaybackProgressCallback();
-    method public void onBufferedPositionChanged(androidx.leanback.widget.PlaybackControlsRow, long);
-    method public void onCurrentPositionChanged(androidx.leanback.widget.PlaybackControlsRow, long);
-    method public void onDurationChanged(androidx.leanback.widget.PlaybackControlsRow, long);
-  }
-
-  public static class PlaybackControlsRow.PictureInPictureAction extends androidx.leanback.widget.Action {
-    ctor public PlaybackControlsRow.PictureInPictureAction(android.content.Context);
-  }
-
-  public static class PlaybackControlsRow.PlayPauseAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
-    field public static final int INDEX_PAUSE = 1; // 0x1
-    field public static final int INDEX_PLAY = 0; // 0x0
-    field public static deprecated int PAUSE;
-    field public static deprecated int PLAY;
-  }
-
-  public static class PlaybackControlsRow.RepeatAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
-    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
-    ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
-    field public static deprecated int ALL;
-    field public static final int INDEX_ALL = 1; // 0x1
-    field public static final int INDEX_NONE = 0; // 0x0
-    field public static final int INDEX_ONE = 2; // 0x2
-    field public static deprecated int NONE;
-    field public static deprecated int ONE;
-  }
-
-  public static class PlaybackControlsRow.RewindAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.RewindAction(android.content.Context);
-    ctor public PlaybackControlsRow.RewindAction(android.content.Context, int);
-  }
-
-  public static class PlaybackControlsRow.ShuffleAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context);
-    ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
-    field public static final int INDEX_OFF = 0; // 0x0
-    field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
-  }
-
-  public static class PlaybackControlsRow.SkipNextAction extends androidx.leanback.widget.Action {
-    ctor public PlaybackControlsRow.SkipNextAction(android.content.Context);
-  }
-
-  public static class PlaybackControlsRow.SkipPreviousAction extends androidx.leanback.widget.Action {
-    ctor public PlaybackControlsRow.SkipPreviousAction(android.content.Context);
-  }
-
-  public static abstract class PlaybackControlsRow.ThumbsAction extends androidx.leanback.widget.PlaybackControlsRow.MultiAction {
-    ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
-    field public static final int INDEX_OUTLINE = 1; // 0x1
-    field public static final int INDEX_SOLID = 0; // 0x0
-    field public static deprecated int OUTLINE;
-    field public static deprecated int SOLID;
-  }
-
-  public static class PlaybackControlsRow.ThumbsDownAction extends androidx.leanback.widget.PlaybackControlsRow.ThumbsAction {
-    ctor public PlaybackControlsRow.ThumbsDownAction(android.content.Context);
-  }
-
-  public static class PlaybackControlsRow.ThumbsUpAction extends androidx.leanback.widget.PlaybackControlsRow.ThumbsAction {
-    ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
-  }
-
-  public class PlaybackControlsRowPresenter extends androidx.leanback.widget.PlaybackRowPresenter {
-    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter);
-    ctor public PlaybackControlsRowPresenter();
-    method public boolean areSecondaryActionsHidden();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method public int getBackgroundColor();
-    method public androidx.leanback.widget.OnActionClickedListener getOnActionClickedListener();
-    method public int getProgressColor();
-    method public void setBackgroundColor(int);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener);
-    method public void setProgressColor(int);
-    method public void setSecondaryActionsHidden(boolean);
-    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
-    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
-  }
-
-  public class PlaybackControlsRowPresenter.ViewHolder extends androidx.leanback.widget.PlaybackRowPresenter.ViewHolder {
-    field public final androidx.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
-  }
-
-  public abstract class PlaybackRowPresenter extends androidx.leanback.widget.RowPresenter {
-    ctor public PlaybackRowPresenter();
-    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder);
-  }
-
-  public static class PlaybackRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public PlaybackRowPresenter.ViewHolder(android.view.View);
-  }
-
-  public class PlaybackSeekDataProvider {
-    ctor public PlaybackSeekDataProvider();
-    method public long[] getSeekPositions();
-    method public void getThumbnail(int, androidx.leanback.widget.PlaybackSeekDataProvider.ResultCallback);
-    method public void reset();
-  }
-
-  public static class PlaybackSeekDataProvider.ResultCallback {
-    ctor public PlaybackSeekDataProvider.ResultCallback();
-    method public void onThumbnailLoaded(android.graphics.Bitmap, int);
-  }
-
-  public abstract interface PlaybackSeekUi {
-    method public abstract void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-  }
-
-  public static class PlaybackSeekUi.Client {
-    ctor public PlaybackSeekUi.Client();
-    method public androidx.leanback.widget.PlaybackSeekDataProvider getPlaybackSeekDataProvider();
-    method public boolean isSeekEnabled();
-    method public void onSeekFinished(boolean);
-    method public void onSeekPositionChanged(long);
-    method public void onSeekStarted();
-  }
-
-  public class PlaybackTransportRowPresenter extends androidx.leanback.widget.PlaybackRowPresenter {
-    ctor public PlaybackTransportRowPresenter();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method public float getDefaultSeekIncrement();
-    method public androidx.leanback.widget.OnActionClickedListener getOnActionClickedListener();
-    method public int getProgressColor();
-    method protected void onProgressBarClicked(androidx.leanback.widget.PlaybackTransportRowPresenter.ViewHolder);
-    method public void setDefaultSeekIncrement(float);
-    method public void setDescriptionPresenter(androidx.leanback.widget.Presenter);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener);
-    method public void setProgressColor(int);
-  }
-
-  public class PlaybackTransportRowPresenter.ViewHolder extends androidx.leanback.widget.PlaybackRowPresenter.ViewHolder implements androidx.leanback.widget.PlaybackSeekUi {
-    ctor public PlaybackTransportRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.Presenter);
-    method public final android.widget.TextView getCurrentPositionView();
-    method public final androidx.leanback.widget.Presenter.ViewHolder getDescriptionViewHolder();
-    method public final android.widget.TextView getDurationView();
-    method protected void onSetCurrentPositionLabel(long);
-    method protected void onSetDurationLabel(long);
-    method public void setPlaybackSeekUiClient(androidx.leanback.widget.PlaybackSeekUi.Client);
-  }
-
-  public abstract class Presenter implements androidx.leanback.widget.FacetProvider {
-    ctor public Presenter();
-    method protected static void cancelAnimationsRecursive(android.view.View);
-    method public final java.lang.Object getFacet(java.lang.Class<?>);
-    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object, java.util.List<java.lang.Object>);
-    method public abstract androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder);
-    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
-    method public void setOnClickListener(androidx.leanback.widget.Presenter.ViewHolder, android.view.View.OnClickListener);
-  }
-
-  public static class Presenter.ViewHolder implements androidx.leanback.widget.FacetProvider {
-    ctor public Presenter.ViewHolder(android.view.View);
-    method public final java.lang.Object getFacet(java.lang.Class<?>);
-    method public final void setFacet(java.lang.Class<?>, java.lang.Object);
-    field public final android.view.View view;
-  }
-
-  public static abstract class Presenter.ViewHolderTask {
-    ctor public Presenter.ViewHolderTask();
-    method public void run(androidx.leanback.widget.Presenter.ViewHolder);
-  }
-
-  public abstract class PresenterSelector {
-    ctor public PresenterSelector();
-    method public abstract androidx.leanback.widget.Presenter getPresenter(java.lang.Object);
-    method public androidx.leanback.widget.Presenter[] getPresenters();
-  }
-
-  public abstract class PresenterSwitcher {
-    ctor public PresenterSwitcher();
-    method public void clear();
-    method public final android.view.ViewGroup getParentViewGroup();
-    method public void init(android.view.ViewGroup, androidx.leanback.widget.PresenterSelector);
-    method protected abstract void insertView(android.view.View);
-    method protected void onViewSelected(android.view.View);
-    method public void select(java.lang.Object);
-    method protected void showView(android.view.View, boolean);
-    method public void unselect();
-  }
-
-  public class RecyclerViewParallax extends androidx.leanback.widget.Parallax {
-    ctor public RecyclerViewParallax();
-    method public androidx.leanback.widget.RecyclerViewParallax.ChildPositionProperty createProperty(java.lang.String, int);
-    method public float getMaxValue();
-    method public androidx.recyclerview.widget.RecyclerView getRecyclerView();
-    method public void setRecyclerView(androidx.recyclerview.widget.RecyclerView);
-  }
-
-  public static final class RecyclerViewParallax.ChildPositionProperty extends androidx.leanback.widget.Parallax.IntProperty {
-    method public androidx.leanback.widget.RecyclerViewParallax.ChildPositionProperty adapterPosition(int);
-    method public androidx.leanback.widget.RecyclerViewParallax.ChildPositionProperty fraction(float);
-    method public int getAdapterPosition();
-    method public float getFraction();
-    method public int getOffset();
-    method public int getViewId();
-    method public androidx.leanback.widget.RecyclerViewParallax.ChildPositionProperty offset(int);
-    method public androidx.leanback.widget.RecyclerViewParallax.ChildPositionProperty viewId(int);
-  }
-
-  public class Row {
-    ctor public Row(long, androidx.leanback.widget.HeaderItem);
-    ctor public Row(androidx.leanback.widget.HeaderItem);
-    ctor public Row();
-    method public final androidx.leanback.widget.HeaderItem getHeaderItem();
-    method public final long getId();
-    method public boolean isRenderedAsRowView();
-    method public final void setHeaderItem(androidx.leanback.widget.HeaderItem);
-    method public final void setId(long);
-  }
-
-  public class RowHeaderPresenter extends androidx.leanback.widget.Presenter {
-    ctor public RowHeaderPresenter();
-    method protected static float getFontDescent(android.widget.TextView, android.graphics.Paint);
-    method public int getSpaceUnderBaseline(androidx.leanback.widget.RowHeaderPresenter.ViewHolder);
-    method public boolean isNullItemVisibilityGone();
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method protected void onSelectLevelChanged(androidx.leanback.widget.RowHeaderPresenter.ViewHolder);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void setNullItemVisibilityGone(boolean);
-    method public final void setSelectLevel(androidx.leanback.widget.RowHeaderPresenter.ViewHolder, float);
-  }
-
-  public static class RowHeaderPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public RowHeaderPresenter.ViewHolder(android.view.View);
-    method public final float getSelectLevel();
-  }
-
-  public final class RowHeaderView extends android.widget.TextView {
-    ctor public RowHeaderView(android.content.Context);
-    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet);
-    ctor public RowHeaderView(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public abstract class RowPresenter extends androidx.leanback.widget.Presenter {
-    ctor public RowPresenter();
-    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
-    method protected void dispatchItemSelectedListener(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
-    method public void freeze(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
-    method public final androidx.leanback.widget.RowHeaderPresenter getHeaderPresenter();
-    method public final androidx.leanback.widget.RowPresenter.ViewHolder getRowViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public final boolean getSelectEffectEnabled();
-    method public final float getSelectLevel(androidx.leanback.widget.Presenter.ViewHolder);
-    method public final int getSyncActivatePolicy();
-    method protected void initializeRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder);
-    method protected boolean isClippingChildren();
-    method public boolean isUsingDefaultSelectEffect();
-    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder, java.lang.Object);
-    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public final androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
-    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
-    method protected void onRowViewExpanded(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
-    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
-    method protected void onSelectLevelChanged(androidx.leanback.widget.RowPresenter.ViewHolder);
-    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder);
-    method public final void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public final void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder);
-    method public final void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
-    method public final void setHeaderPresenter(androidx.leanback.widget.RowHeaderPresenter);
-    method public final void setRowViewExpanded(androidx.leanback.widget.Presenter.ViewHolder, boolean);
-    method public final void setRowViewSelected(androidx.leanback.widget.Presenter.ViewHolder, boolean);
-    method public final void setSelectEffectEnabled(boolean);
-    method public final void setSelectLevel(androidx.leanback.widget.Presenter.ViewHolder, float);
-    method public final void setSyncActivatePolicy(int);
-    field public static final int SYNC_ACTIVATED_CUSTOM = 0; // 0x0
-    field public static final int SYNC_ACTIVATED_TO_EXPANDED = 1; // 0x1
-    field public static final int SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED = 3; // 0x3
-    field public static final int SYNC_ACTIVATED_TO_SELECTED = 2; // 0x2
-  }
-
-  public static class RowPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public RowPresenter.ViewHolder(android.view.View);
-    method public final androidx.leanback.widget.RowHeaderPresenter.ViewHolder getHeaderViewHolder();
-    method public final androidx.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
-    method public final androidx.leanback.widget.BaseOnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public android.view.View.OnKeyListener getOnKeyListener();
-    method public final androidx.leanback.widget.Row getRow();
-    method public final java.lang.Object getRowObject();
-    method public final float getSelectLevel();
-    method public java.lang.Object getSelectedItem();
-    method public androidx.leanback.widget.Presenter.ViewHolder getSelectedItemViewHolder();
-    method public final boolean isExpanded();
-    method public final boolean isSelected();
-    method public final void setActivated(boolean);
-    method public final void setOnItemViewClickedListener(androidx.leanback.widget.BaseOnItemViewClickedListener);
-    method public final void setOnItemViewSelectedListener(androidx.leanback.widget.BaseOnItemViewSelectedListener);
-    method public void setOnKeyListener(android.view.View.OnKeyListener);
-    method public final void syncActivatedStatus(android.view.View);
-    field protected final androidx.leanback.graphics.ColorOverlayDimmer mColorDimmer;
-  }
-
-  public class SearchBar extends android.widget.RelativeLayout {
-    ctor public SearchBar(android.content.Context);
-    ctor public SearchBar(android.content.Context, android.util.AttributeSet);
-    ctor public SearchBar(android.content.Context, android.util.AttributeSet, int);
-    method public void displayCompletions(java.util.List<java.lang.String>);
-    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public java.lang.CharSequence getHint();
-    method public java.lang.String getTitle();
-    method public boolean isRecognizing();
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setPermissionListener(androidx.leanback.widget.SearchBar.SearchBarPermissionListener);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchAffordanceColorsInListening(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSearchBarListener(androidx.leanback.widget.SearchBar.SearchBarListener);
-    method public void setSearchQuery(java.lang.String);
-    method public deprecated void setSpeechRecognitionCallback(androidx.leanback.widget.SpeechRecognitionCallback);
-    method public void setSpeechRecognizer(android.speech.SpeechRecognizer);
-    method public void setTitle(java.lang.String);
-    method public void startRecognition();
-    method public void stopRecognition();
-  }
-
-  public static abstract interface SearchBar.SearchBarListener {
-    method public abstract void onKeyboardDismiss(java.lang.String);
-    method public abstract void onSearchQueryChange(java.lang.String);
-    method public abstract void onSearchQuerySubmit(java.lang.String);
-  }
-
-  public static abstract interface SearchBar.SearchBarPermissionListener {
-    method public abstract void requestAudioPermission();
-  }
-
-  public class SearchEditText extends android.widget.EditText {
-    ctor public SearchEditText(android.content.Context);
-    ctor public SearchEditText(android.content.Context, android.util.AttributeSet);
-    ctor public SearchEditText(android.content.Context, android.util.AttributeSet, int);
-    method public void setOnKeyboardDismissListener(androidx.leanback.widget.SearchEditText.OnKeyboardDismissListener);
-  }
-
-  public static abstract interface SearchEditText.OnKeyboardDismissListener {
-    method public abstract void onKeyboardDismiss();
-  }
-
-  public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
-    ctor public SearchOrbView(android.content.Context);
-    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet);
-    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet, int);
-    method public void enableOrbColorAnimation(boolean);
-    method public int getOrbColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors getOrbColors();
-    method public android.graphics.drawable.Drawable getOrbIcon();
-    method public void onClick(android.view.View);
-    method public void setOnOrbClickedListener(android.view.View.OnClickListener);
-    method public void setOrbColor(int);
-    method public deprecated void setOrbColor(int, int);
-    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setOrbIcon(android.graphics.drawable.Drawable);
-  }
-
-  public static class SearchOrbView.Colors {
-    ctor public SearchOrbView.Colors(int);
-    ctor public SearchOrbView.Colors(int, int);
-    ctor public SearchOrbView.Colors(int, int, int);
-    method public static int getBrightColor(int);
-    field public int brightColor;
-    field public int color;
-    field public int iconColor;
-  }
-
-  public class SectionRow extends androidx.leanback.widget.Row {
-    ctor public SectionRow(androidx.leanback.widget.HeaderItem);
-    ctor public SectionRow(long, java.lang.String);
-    ctor public SectionRow(java.lang.String);
-    method public final boolean isRenderedAsRowView();
-  }
-
-  public class ShadowOverlayContainer extends android.widget.FrameLayout {
-    ctor public ShadowOverlayContainer(android.content.Context);
-    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet);
-    ctor public ShadowOverlayContainer(android.content.Context, android.util.AttributeSet, int);
-    method public int getShadowType();
-    method public android.view.View getWrappedView();
-    method public deprecated void initialize(boolean, boolean);
-    method public deprecated void initialize(boolean, boolean, boolean);
-    method public static void prepareParentForShadow(android.view.ViewGroup);
-    method public void setOverlayColor(int);
-    method public void setShadowFocusLevel(float);
-    method public static boolean supportsDynamicShadow();
-    method public static boolean supportsShadow();
-    method public void useDynamicShadow();
-    method public void useDynamicShadow(float, float);
-    method public void useStaticShadow();
-    method public void wrap(android.view.View);
-    field public static final int SHADOW_DYNAMIC = 3; // 0x3
-    field public static final int SHADOW_NONE = 1; // 0x1
-    field public static final int SHADOW_STATIC = 2; // 0x2
-  }
-
-  public final class ShadowOverlayHelper {
-    method public androidx.leanback.widget.ShadowOverlayContainer createShadowOverlayContainer(android.content.Context);
-    method public int getShadowType();
-    method public boolean needsOverlay();
-    method public boolean needsRoundedCorner();
-    method public boolean needsWrapper();
-    method public void onViewCreated(android.view.View);
-    method public void prepareParentForShadow(android.view.ViewGroup);
-    method public static void setNoneWrapperOverlayColor(android.view.View, int);
-    method public static void setNoneWrapperShadowFocusLevel(android.view.View, float);
-    method public void setOverlayColor(android.view.View, int);
-    method public void setShadowFocusLevel(android.view.View, float);
-    method public static boolean supportsDynamicShadow();
-    method public static boolean supportsForeground();
-    method public static boolean supportsRoundedCorner();
-    method public static boolean supportsShadow();
-    field public static final int SHADOW_DYNAMIC = 3; // 0x3
-    field public static final int SHADOW_NONE = 1; // 0x1
-    field public static final int SHADOW_STATIC = 2; // 0x2
-  }
-
-  public static final class ShadowOverlayHelper.Builder {
-    ctor public ShadowOverlayHelper.Builder();
-    method public androidx.leanback.widget.ShadowOverlayHelper build(android.content.Context);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder keepForegroundDrawable(boolean);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder needsOverlay(boolean);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder needsRoundedCorner(boolean);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder needsShadow(boolean);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder options(androidx.leanback.widget.ShadowOverlayHelper.Options);
-    method public androidx.leanback.widget.ShadowOverlayHelper.Builder preferZOrder(boolean);
-  }
-
-  public static final class ShadowOverlayHelper.Options {
-    ctor public ShadowOverlayHelper.Options();
-    method public androidx.leanback.widget.ShadowOverlayHelper.Options dynamicShadowZ(float, float);
-    method public float getDynamicShadowFocusedZ();
-    method public float getDynamicShadowUnfocusedZ();
-    method public int getRoundedCornerRadius();
-    method public androidx.leanback.widget.ShadowOverlayHelper.Options roundedCornerRadius(int);
-    field public static final androidx.leanback.widget.ShadowOverlayHelper.Options DEFAULT;
-  }
-
-  public final class SinglePresenterSelector extends androidx.leanback.widget.PresenterSelector {
-    ctor public SinglePresenterSelector(androidx.leanback.widget.Presenter);
-    method public androidx.leanback.widget.Presenter getPresenter(java.lang.Object);
-  }
-
-  public class SparseArrayObjectAdapter extends androidx.leanback.widget.ObjectAdapter {
-    ctor public SparseArrayObjectAdapter(androidx.leanback.widget.PresenterSelector);
-    ctor public SparseArrayObjectAdapter(androidx.leanback.widget.Presenter);
-    ctor public SparseArrayObjectAdapter();
-    method public void clear(int);
-    method public void clear();
-    method public java.lang.Object get(int);
-    method public int indexOf(java.lang.Object);
-    method public int indexOf(int);
-    method public java.lang.Object lookup(int);
-    method public void notifyArrayItemRangeChanged(int, int);
-    method public void set(int, java.lang.Object);
-    method public int size();
-  }
-
-  public class SpeechOrbView extends androidx.leanback.widget.SearchOrbView {
-    ctor public SpeechOrbView(android.content.Context);
-    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
-    ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
-    method public void setListeningOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setNotListeningOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setSoundLevel(int);
-    method public void showListening();
-    method public void showNotListening();
-  }
-
-  public abstract deprecated interface SpeechRecognitionCallback {
-    method public abstract void recognizeSpeech();
-  }
-
-  public class TitleHelper {
-    ctor public TitleHelper(android.view.ViewGroup, android.view.View);
-    method public androidx.leanback.widget.BrowseFrameLayout.OnFocusSearchListener getOnFocusSearchListener();
-    method public android.view.ViewGroup getSceneRoot();
-    method public android.view.View getTitleView();
-    method public void showTitle(boolean);
-  }
-
-  public class TitleView extends android.widget.FrameLayout implements androidx.leanback.widget.TitleViewAdapter.Provider {
-    ctor public TitleView(android.content.Context);
-    ctor public TitleView(android.content.Context, android.util.AttributeSet);
-    ctor public TitleView(android.content.Context, android.util.AttributeSet, int);
-    method public void enableAnimation(boolean);
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public androidx.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
-    method public android.view.View getSearchAffordanceView();
-    method public java.lang.CharSequence getTitle();
-    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setTitle(java.lang.CharSequence);
-    method public void updateComponentsVisibility(int);
-  }
-
-  public abstract class TitleViewAdapter {
-    ctor public TitleViewAdapter();
-    method public android.graphics.drawable.Drawable getBadgeDrawable();
-    method public androidx.leanback.widget.SearchOrbView.Colors getSearchAffordanceColors();
-    method public abstract android.view.View getSearchAffordanceView();
-    method public java.lang.CharSequence getTitle();
-    method public void setAnimationEnabled(boolean);
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
-    method public void setTitle(java.lang.CharSequence);
-    method public void updateComponentsVisibility(int);
-    field public static final int BRANDING_VIEW_VISIBLE = 2; // 0x2
-    field public static final int FULL_VIEW_VISIBLE = 6; // 0x6
-    field public static final int SEARCH_VIEW_VISIBLE = 4; // 0x4
-  }
-
-  public static abstract interface TitleViewAdapter.Provider {
-    method public abstract androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
-  }
-
-  public class VerticalGridPresenter extends androidx.leanback.widget.Presenter {
-    ctor public VerticalGridPresenter();
-    ctor public VerticalGridPresenter(int);
-    ctor public VerticalGridPresenter(int, boolean);
-    method public final boolean areChildRoundedCornersEnabled();
-    method protected androidx.leanback.widget.VerticalGridPresenter.ViewHolder createGridViewHolder(android.view.ViewGroup);
-    method protected androidx.leanback.widget.ShadowOverlayHelper.Options createShadowOverlayOptions();
-    method public final void enableChildRoundedCorners(boolean);
-    method public final int getFocusZoomFactor();
-    method public final boolean getKeepChildForeground();
-    method public int getNumberOfColumns();
-    method public final androidx.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public final androidx.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
-    method public final boolean getShadowEnabled();
-    method protected void initializeGridViewHolder(androidx.leanback.widget.VerticalGridPresenter.ViewHolder);
-    method public final boolean isFocusDimmerUsed();
-    method public boolean isUsingDefaultShadow();
-    method public boolean isUsingZOrder(android.content.Context);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, java.lang.Object);
-    method public final androidx.leanback.widget.VerticalGridPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
-    method public void setEntranceTransitionState(androidx.leanback.widget.VerticalGridPresenter.ViewHolder, boolean);
-    method public final void setKeepChildForeground(boolean);
-    method public void setNumberOfColumns(int);
-    method public final void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener);
-    method public final void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener);
-    method public final void setShadowEnabled(boolean);
-  }
-
-  public static class VerticalGridPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public VerticalGridPresenter.ViewHolder(androidx.leanback.widget.VerticalGridView);
-    method public androidx.leanback.widget.VerticalGridView getGridView();
-  }
-
-  public class VerticalGridView extends androidx.leanback.widget.BaseGridView {
-    ctor public VerticalGridView(android.content.Context);
-    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet);
-    ctor public VerticalGridView(android.content.Context, android.util.AttributeSet, int);
-    method protected void initAttributes(android.content.Context, android.util.AttributeSet);
-    method public void setColumnWidth(int);
-    method public void setNumColumns(int);
-  }
-
-  public abstract interface ViewHolderTask {
-    method public abstract void run(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-  }
-
-}
-
-package androidx.leanback.widget.picker {
-
-  public class Picker extends android.widget.FrameLayout {
-    ctor public Picker(android.content.Context, android.util.AttributeSet, int);
-    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
-    method public float getActivatedVisibleItemCount();
-    method public androidx.leanback.widget.picker.PickerColumn getColumnAt(int);
-    method public int getColumnsCount();
-    method protected int getPickerItemHeightPixels();
-    method public final int getPickerItemLayoutId();
-    method public final int getPickerItemTextViewId();
-    method public int getSelectedColumn();
-    method public final deprecated java.lang.CharSequence getSeparator();
-    method public final java.util.List<java.lang.CharSequence> getSeparators();
-    method public float getVisibleItemCount();
-    method public void onColumnValueChanged(int, int);
-    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
-    method public void setActivatedVisibleItemCount(float);
-    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn);
-    method public void setColumnValue(int, int, boolean);
-    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn>);
-    method public final void setPickerItemTextViewId(int);
-    method public void setSelectedColumn(int);
-    method public final void setSeparator(java.lang.CharSequence);
-    method public final void setSeparators(java.util.List<java.lang.CharSequence>);
-    method public void setVisibleItemCount(float);
-  }
-
-  public static abstract interface Picker.PickerValueListener {
-    method public abstract void onValueChanged(androidx.leanback.widget.picker.Picker, int);
-  }
-
-  public class PickerColumn {
-    ctor public PickerColumn();
-    method public int getCount();
-    method public int getCurrentValue();
-    method public java.lang.CharSequence getLabelFor(int);
-    method public java.lang.String getLabelFormat();
-    method public int getMaxValue();
-    method public int getMinValue();
-    method public java.lang.CharSequence[] getStaticLabels();
-    method public void setCurrentValue(int);
-    method public void setLabelFormat(java.lang.String);
-    method public void setMaxValue(int);
-    method public void setMinValue(int);
-    method public void setStaticLabels(java.lang.CharSequence[]);
-  }
-
-  public class TimePicker extends androidx.leanback.widget.picker.Picker {
-    ctor public TimePicker(android.content.Context, android.util.AttributeSet);
-    ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
-    method public int getHour();
-    method public int getMinute();
-    method public boolean is24Hour();
-    method public boolean isPm();
-    method public void setHour(int);
-    method public void setIs24Hour(boolean);
-    method public void setMinute(int);
-  }
-
-}
-
diff --git a/libraryversions.toml b/libraryversions.toml
index d20f1d7..b2c6145 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -67,7 +67,7 @@
 GRAPHICS_SHAPES = "1.0.0-alpha03"
 GRIDLAYOUT = "1.1.0-beta02"
 HEALTH_CONNECT = "1.0.0-alpha11"
-HEALTH_SERVICES_CLIENT = "1.0.0-beta04"
+HEALTH_SERVICES_CLIENT = "1.0.0-rc01"
 HEIFWRITER = "1.1.0-alpha02"
 HILT = "1.1.0-alpha03"
 HILT_NAVIGATION_COMPOSE = "1.1.0-alpha02"
@@ -142,7 +142,7 @@
 VIEWPAGER2 = "1.1.0-beta03"
 WEAR = "1.3.0-beta01"
 WEAR_COMPOSE = "1.3.0-alpha01"
-WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha05"
+WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha07"
 WEAR_INPUT = "1.2.0-alpha03"
 WEAR_INPUT_TESTING = "1.2.0-alpha03"
 WEAR_ONGOING = "1.1.0-alpha01"
diff --git a/lifecycle/lifecycle-viewmodel-compose/src/main/java/androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt b/lifecycle/lifecycle-viewmodel-compose/src/main/java/androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt
index 9620449..1eb3d21 100644
--- a/lifecycle/lifecycle-viewmodel-compose/src/main/java/androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt
+++ b/lifecycle/lifecycle-viewmodel-compose/src/main/java/androidx/lifecycle/viewmodel/compose/SavedStateHandleSaver.kt
@@ -184,7 +184,7 @@
             }
             mutableStateOf(save(state.value), state.policy as SnapshotMutationPolicy<Any?>)
         },
-        restore = @Suppress("UNCHECKED_CAST") {
+        restore = @Suppress("UNCHECKED_CAST", "ExceptionMessage") {
             require(it is SnapshotMutableState<Any?>)
             mutableStateOf(
                 if (it.value != null) restore(it.value!!) else null,
diff --git a/loader/loader/api/0.0.0.txt b/loader/loader/api/0.0.0.txt
deleted file mode 100644
index d9bbf32..0000000
--- a/loader/loader/api/0.0.0.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-package androidx.loader.app {
-
-  public abstract class LoaderManager {
-    ctor public LoaderManager();
-    method public abstract void destroyLoader(int);
-    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public static void enableDebugLogging(boolean);
-    method public abstract <D> androidx.loader.content.Loader<D> getLoader(int);
-    method public boolean hasRunningLoaders();
-    method public abstract <D> androidx.loader.content.Loader<D> initLoader(int, android.os.Bundle, androidx.loader.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract <D> androidx.loader.content.Loader<D> restartLoader(int, android.os.Bundle, androidx.loader.app.LoaderManager.LoaderCallbacks<D>);
-  }
-
-  public static abstract interface LoaderManager.LoaderCallbacks<D> {
-    method public abstract androidx.loader.content.Loader<D> onCreateLoader(int, android.os.Bundle);
-    method public abstract void onLoadFinished(androidx.loader.content.Loader<D>, D);
-    method public abstract void onLoaderReset(androidx.loader.content.Loader<D>);
-  }
-
-}
\ No newline at end of file
diff --git a/media/media/api/0.0.0.txt b/media/media/api/0.0.0.txt
deleted file mode 100644
index d4490b3..0000000
--- a/media/media/api/0.0.0.txt
+++ /dev/null
@@ -1,660 +0,0 @@
-package android.support.v4.media {
-
-  public final class MediaBrowserCompat {
-    ctor public MediaBrowserCompat(android.content.Context, android.content.ComponentName, android.support.v4.media.MediaBrowserCompat.ConnectionCallback, android.os.Bundle);
-    method public void connect();
-    method public void disconnect();
-    method public android.os.Bundle getExtras();
-    method public void getItem(java.lang.String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
-    method public java.lang.String getRoot();
-    method public android.content.ComponentName getServiceComponent();
-    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
-    method public boolean isConnected();
-    method public void search(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SearchCallback);
-    method public void sendCustomAction(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.CustomActionCallback);
-    method public void subscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
-    method public void subscribe(java.lang.String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
-    method public void unsubscribe(java.lang.String);
-    method public void unsubscribe(java.lang.String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
-    field public static final java.lang.String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
-    field public static final java.lang.String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
-    field public static final java.lang.String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
-    field public static final java.lang.String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
-    field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-    field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
-  }
-
-  public static class MediaBrowserCompat.ConnectionCallback {
-    ctor public MediaBrowserCompat.ConnectionCallback();
-    method public void onConnected();
-    method public void onConnectionFailed();
-    method public void onConnectionSuspended();
-  }
-
-  public static abstract class MediaBrowserCompat.CustomActionCallback {
-    ctor public MediaBrowserCompat.CustomActionCallback();
-    method public void onError(java.lang.String, android.os.Bundle, android.os.Bundle);
-    method public void onProgressUpdate(java.lang.String, android.os.Bundle, android.os.Bundle);
-    method public void onResult(java.lang.String, android.os.Bundle, android.os.Bundle);
-  }
-
-  public static abstract class MediaBrowserCompat.ItemCallback {
-    ctor public MediaBrowserCompat.ItemCallback();
-    method public void onError(java.lang.String);
-    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem);
-  }
-
-  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
-    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
-    method public int describeContents();
-    method public static android.support.v4.media.MediaBrowserCompat.MediaItem fromMediaItem(java.lang.Object);
-    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> fromMediaItemList(java.util.List<?>);
-    method public android.support.v4.media.MediaDescriptionCompat getDescription();
-    method public int getFlags();
-    method public java.lang.String getMediaId();
-    method public boolean isBrowsable();
-    method public boolean isPlayable();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem> CREATOR;
-    field public static final int FLAG_BROWSABLE = 1; // 0x1
-    field public static final int FLAG_PLAYABLE = 2; // 0x2
-  }
-
-  public static abstract class MediaBrowserCompat.SearchCallback {
-    ctor public MediaBrowserCompat.SearchCallback();
-    method public void onError(java.lang.String, android.os.Bundle);
-    method public void onSearchResult(java.lang.String, android.os.Bundle, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
-  }
-
-  public static abstract class MediaBrowserCompat.SubscriptionCallback {
-    ctor public MediaBrowserCompat.SubscriptionCallback();
-    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>);
-    method public void onChildrenLoaded(java.lang.String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>, android.os.Bundle);
-    method public void onError(java.lang.String);
-    method public void onError(java.lang.String, android.os.Bundle);
-  }
-
-  public final class RatingCompat implements android.os.Parcelable {
-    method public int describeContents();
-    method public static android.support.v4.media.RatingCompat fromRating(java.lang.Object);
-    method public float getPercentRating();
-    method public java.lang.Object getRating();
-    method public int getRatingStyle();
-    method public float getStarRating();
-    method public boolean hasHeart();
-    method public boolean isRated();
-    method public boolean isThumbUp();
-    method public static android.support.v4.media.RatingCompat newHeartRating(boolean);
-    method public static android.support.v4.media.RatingCompat newPercentageRating(float);
-    method public static android.support.v4.media.RatingCompat newStarRating(int, float);
-    method public static android.support.v4.media.RatingCompat newThumbRating(boolean);
-    method public static android.support.v4.media.RatingCompat newUnratedRating(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat> CREATOR;
-    field public static final int RATING_3_STARS = 3; // 0x3
-    field public static final int RATING_4_STARS = 4; // 0x4
-    field public static final int RATING_5_STARS = 5; // 0x5
-    field public static final int RATING_HEART = 1; // 0x1
-    field public static final int RATING_NONE = 0; // 0x0
-    field public static final int RATING_PERCENTAGE = 6; // 0x6
-    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
-  }
-
-
-  public final class MediaDescriptionCompat implements android.os.Parcelable {
-    method public int describeContents();
-    method public static android.support.v4.media.MediaDescriptionCompat fromMediaDescription(java.lang.Object);
-    method public java.lang.CharSequence getDescription();
-    method public android.os.Bundle getExtras();
-    method public android.graphics.Bitmap getIconBitmap();
-    method public android.net.Uri getIconUri();
-    method public java.lang.Object getMediaDescription();
-    method public java.lang.String getMediaId();
-    method public android.net.Uri getMediaUri();
-    method public java.lang.CharSequence getSubtitle();
-    method public java.lang.CharSequence getTitle();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
-    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
-    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
-    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
-    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
-    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
-    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat> CREATOR;
-    field public static final java.lang.String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
-    field public static final java.lang.String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
-    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
-    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
-    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
-  }
-
-  public static final class MediaDescriptionCompat.Builder {
-    ctor public MediaDescriptionCompat.Builder();
-    method public android.support.v4.media.MediaDescriptionCompat build();
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setDescription(java.lang.CharSequence);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setExtras(android.os.Bundle);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconBitmap(android.graphics.Bitmap);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setIconUri(android.net.Uri);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaId(java.lang.String);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setMediaUri(android.net.Uri);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setSubtitle(java.lang.CharSequence);
-    method public android.support.v4.media.MediaDescriptionCompat.Builder setTitle(java.lang.CharSequence);
-  }
-
-  public final class MediaMetadataCompat implements android.os.Parcelable {
-    method public boolean containsKey(java.lang.String);
-    method public int describeContents();
-    method public static android.support.v4.media.MediaMetadataCompat fromMediaMetadata(java.lang.Object);
-    method public android.graphics.Bitmap getBitmap(java.lang.String);
-    method public android.os.Bundle getBundle();
-    method public android.support.v4.media.MediaDescriptionCompat getDescription();
-    method public long getLong(java.lang.String);
-    method public java.lang.Object getMediaMetadata();
-    method public android.support.v4.media.RatingCompat getRating(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.CharSequence getText(java.lang.String);
-    method public java.util.Set<java.lang.String> keySet();
-    method public int size();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat> CREATOR;
-    field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
-    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
-    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
-    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
-    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-    field public static final java.lang.String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
-    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
-    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-  }
-
-  public static final class MediaMetadataCompat.Builder {
-    ctor public MediaMetadataCompat.Builder();
-    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat);
-    method public android.support.v4.media.MediaMetadataCompat build();
-    method public android.support.v4.media.MediaMetadataCompat.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
-    method public android.support.v4.media.MediaMetadataCompat.Builder putLong(java.lang.String, long);
-    method public android.support.v4.media.MediaMetadataCompat.Builder putRating(java.lang.String, android.support.v4.media.RatingCompat);
-    method public android.support.v4.media.MediaMetadataCompat.Builder putString(java.lang.String, java.lang.String);
-    method public android.support.v4.media.MediaMetadataCompat.Builder putText(java.lang.String, java.lang.CharSequence);
-  }
-
-}
-
-package android.support.v4.media.session {
-
-  public final class MediaControllerCompat {
-    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat);
-    ctor public MediaControllerCompat(android.content.Context, android.support.v4.media.session.MediaSessionCompat.Token) throws android.os.RemoteException;
-    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat);
-    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
-    method public void adjustVolume(int, int);
-    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
-    method public android.os.Bundle getExtras();
-    method public long getFlags();
-    method public static android.support.v4.media.session.MediaControllerCompat getMediaController(android.app.Activity);
-    method public java.lang.Object getMediaController();
-    method public android.support.v4.media.MediaMetadataCompat getMetadata();
-    method public java.lang.String getPackageName();
-    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo getPlaybackInfo();
-    method public android.support.v4.media.session.PlaybackStateCompat getPlaybackState();
-    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
-    method public java.lang.CharSequence getQueueTitle();
-    method public int getRatingType();
-    method public int getRepeatMode();
-    method public android.app.PendingIntent getSessionActivity();
-    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
-    method public int getShuffleMode();
-    method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
-    method public boolean isCaptioningEnabled();
-    method public boolean isSessionReady();
-    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
-    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
-    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat);
-    method public deprecated void removeQueueItemAt(int);
-    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat);
-    method public void setVolumeTo(int, int);
-    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
-  }
-
-  public static abstract class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
-    ctor public MediaControllerCompat.Callback();
-    method public void binderDied();
-    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo);
-    method public void onCaptioningEnabledChanged(boolean);
-    method public void onExtrasChanged(android.os.Bundle);
-    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat);
-    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
-    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
-    method public void onQueueTitleChanged(java.lang.CharSequence);
-    method public void onRepeatModeChanged(int);
-    method public void onSessionDestroyed();
-    method public void onSessionEvent(java.lang.String, android.os.Bundle);
-    method public void onSessionReady();
-    method public void onShuffleModeChanged(int);
-  }
-
-  public static final class MediaControllerCompat.PlaybackInfo {
-    method public int getAudioStream();
-    method public int getCurrentVolume();
-    method public int getMaxVolume();
-    method public int getPlaybackType();
-    method public int getVolumeControl();
-    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
-    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
-  }
-
-  public static abstract class MediaControllerCompat.TransportControls {
-    method public abstract void fastForward();
-    method public abstract void pause();
-    method public abstract void play();
-    method public abstract void playFromMediaId(java.lang.String, android.os.Bundle);
-    method public abstract void playFromSearch(java.lang.String, android.os.Bundle);
-    method public abstract void playFromUri(android.net.Uri, android.os.Bundle);
-    method public abstract void prepare();
-    method public abstract void prepareFromMediaId(java.lang.String, android.os.Bundle);
-    method public abstract void prepareFromSearch(java.lang.String, android.os.Bundle);
-    method public abstract void prepareFromUri(android.net.Uri, android.os.Bundle);
-    method public abstract void rewind();
-    method public abstract void seekTo(long);
-    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
-    method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
-    method public abstract void setCaptioningEnabled(boolean);
-    method public abstract void setRating(android.support.v4.media.RatingCompat);
-    method public abstract void setRating(android.support.v4.media.RatingCompat, android.os.Bundle);
-    method public abstract void setRepeatMode(int);
-    method public abstract void setShuffleMode(int);
-    method public abstract void skipToNext();
-    method public abstract void skipToPrevious();
-    method public abstract void skipToQueueItem(long);
-    method public abstract void stop();
-    field public static final java.lang.String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
-  }
-
-
-  public class MediaSessionCompat {
-    ctor public MediaSessionCompat(android.content.Context, java.lang.String);
-    ctor public MediaSessionCompat(android.content.Context, java.lang.String, android.content.ComponentName, android.app.PendingIntent);
-    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
-    method public static android.support.v4.media.session.MediaSessionCompat fromMediaSession(android.content.Context, java.lang.Object);
-    method public android.support.v4.media.session.MediaControllerCompat getController();
-    method public java.lang.Object getMediaSession();
-    method public java.lang.Object getRemoteControlClient();
-    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
-    method public boolean isActive();
-    method public void release();
-    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener);
-    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
-    method public void setActive(boolean);
-    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback);
-    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback, android.os.Handler);
-    method public void setCaptioningEnabled(boolean);
-    method public void setExtras(android.os.Bundle);
-    method public void setFlags(int);
-    method public void setMediaButtonReceiver(android.app.PendingIntent);
-    method public void setMetadata(android.support.v4.media.MediaMetadataCompat);
-    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat);
-    method public void setPlaybackToLocal(int);
-    method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat);
-    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
-    method public void setQueueTitle(java.lang.CharSequence);
-    method public void setRatingType(int);
-    method public void setRepeatMode(int);
-    method public void setSessionActivity(android.app.PendingIntent);
-    method public void setShuffleMode(int);
-    field public static final java.lang.String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
-    field public static final java.lang.String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
-    field public static final java.lang.String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
-    field public static final java.lang.String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
-    field public static final java.lang.String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
-    field public static final java.lang.String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
-    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
-    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
-    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
-    field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
-    field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
-    field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
-  }
-
-  public static abstract class MediaSessionCompat.Callback {
-    ctor public MediaSessionCompat.Callback();
-    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat);
-    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat, int);
-    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onCustomAction(java.lang.String, android.os.Bundle);
-    method public void onFastForward();
-    method public boolean onMediaButtonEvent(android.content.Intent);
-    method public void onPause();
-    method public void onPlay();
-    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
-    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
-    method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
-    method public void onPrepare();
-    method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
-    method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
-    method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
-    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat);
-    method public deprecated void onRemoveQueueItemAt(int);
-    method public void onRewind();
-    method public void onSeekTo(long);
-    method public void onSetCaptioningEnabled(boolean);
-    method public void onSetRating(android.support.v4.media.RatingCompat);
-    method public void onSetRating(android.support.v4.media.RatingCompat, android.os.Bundle);
-    method public void onSetRepeatMode(int);
-    method public void onSetShuffleMode(int);
-    method public void onSkipToNext();
-    method public void onSkipToPrevious();
-    method public void onSkipToQueueItem(long);
-    method public void onStop();
-  }
-
-  public static abstract interface MediaSessionCompat.OnActiveChangeListener {
-    method public abstract void onActiveChanged();
-  }
-
-  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
-    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat, long);
-    method public int describeContents();
-    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem fromQueueItem(java.lang.Object);
-    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> fromQueueItemList(java.util.List<?>);
-    method public android.support.v4.media.MediaDescriptionCompat getDescription();
-    method public long getQueueId();
-    method public java.lang.Object getQueueItem();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem> CREATOR;
-    field public static final int UNKNOWN_ID = -1; // 0xffffffff
-  }
-
-  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
-    method public int describeContents();
-    method public static android.support.v4.media.session.MediaSessionCompat.Token fromToken(java.lang.Object);
-    method public java.lang.Object getToken();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token> CREATOR;
-  }
-
-  public class ParcelableVolumeInfo implements android.os.Parcelable {
-    ctor public ParcelableVolumeInfo(int, int, int, int, int);
-    ctor public ParcelableVolumeInfo(android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo> CREATOR;
-    field public int audioStream;
-    field public int controlType;
-    field public int currentVolume;
-    field public int maxVolume;
-    field public int volumeType;
-  }
-
-
-  public final class PlaybackStateCompat implements android.os.Parcelable {
-    method public int describeContents();
-    method public static android.support.v4.media.session.PlaybackStateCompat fromPlaybackState(java.lang.Object);
-    method public long getActions();
-    method public long getActiveQueueItemId();
-    method public long getBufferedPosition();
-    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction> getCustomActions();
-    method public int getErrorCode();
-    method public java.lang.CharSequence getErrorMessage();
-    method public android.os.Bundle getExtras();
-    method public long getLastPositionUpdateTime();
-    method public float getPlaybackSpeed();
-    method public java.lang.Object getPlaybackState();
-    method public long getPosition();
-    method public int getState();
-    method public static int toKeyCode(long);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
-    field public static final long ACTION_PAUSE = 2L; // 0x2L
-    field public static final long ACTION_PLAY = 4L; // 0x4L
-    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
-    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
-    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
-    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
-    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
-    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
-    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
-    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
-    field public static final long ACTION_REWIND = 8L; // 0x8L
-    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
-    field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
-    field public static final long ACTION_SET_RATING = 128L; // 0x80L
-    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
-    field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
-    field public static final deprecated long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
-    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
-    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
-    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
-    field public static final long ACTION_STOP = 1L; // 0x1L
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
-    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
-    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
-    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
-    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
-    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
-    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
-    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
-    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
-    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
-    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
-    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
-    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
-    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
-    field public static final int REPEAT_MODE_ALL = 2; // 0x2
-    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
-    field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
-    field public static final int REPEAT_MODE_NONE = 0; // 0x0
-    field public static final int REPEAT_MODE_ONE = 1; // 0x1
-    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
-    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
-    field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
-    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
-    field public static final int STATE_BUFFERING = 6; // 0x6
-    field public static final int STATE_CONNECTING = 8; // 0x8
-    field public static final int STATE_ERROR = 7; // 0x7
-    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
-    field public static final int STATE_NONE = 0; // 0x0
-    field public static final int STATE_PAUSED = 2; // 0x2
-    field public static final int STATE_PLAYING = 3; // 0x3
-    field public static final int STATE_REWINDING = 5; // 0x5
-    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
-    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
-    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
-    field public static final int STATE_STOPPED = 1; // 0x1
-  }
-
-  public static final class PlaybackStateCompat.Builder {
-    ctor public PlaybackStateCompat.Builder();
-    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(java.lang.String, java.lang.String, int);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction);
-    method public android.support.v4.media.session.PlaybackStateCompat build();
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActions(long);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setActiveQueueItemId(long);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setBufferedPosition(long);
-    method public deprecated android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(java.lang.CharSequence);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setErrorMessage(int, java.lang.CharSequence);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setExtras(android.os.Bundle);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float);
-    method public android.support.v4.media.session.PlaybackStateCompat.Builder setState(int, long, float, long);
-  }
-
-  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
-    method public int describeContents();
-    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction fromCustomAction(java.lang.Object);
-    method public java.lang.String getAction();
-    method public java.lang.Object getCustomAction();
-    method public android.os.Bundle getExtras();
-    method public int getIcon();
-    method public java.lang.CharSequence getName();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction> CREATOR;
-  }
-
-  public static final class PlaybackStateCompat.CustomAction.Builder {
-    ctor public PlaybackStateCompat.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
-    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction build();
-    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder setExtras(android.os.Bundle);
-  }
-
-}
-
-package androidx.media {
-
-  public class AudioAttributesCompat {
-    method public int getContentType();
-    method public int getFlags();
-    method public int getLegacyStreamType();
-    method public int getUsage();
-    method public int getVolumeControlStream();
-    method public java.lang.Object unwrap();
-    method public static androidx.media.AudioAttributesCompat wrap(java.lang.Object);
-    field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
-    field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
-    field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
-    field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
-    field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
-    field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
-    field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
-    field public static final int USAGE_ALARM = 4; // 0x4
-    field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
-    field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
-    field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
-    field public static final int USAGE_ASSISTANT = 16; // 0x10
-    field public static final int USAGE_GAME = 14; // 0xe
-    field public static final int USAGE_MEDIA = 1; // 0x1
-    field public static final int USAGE_NOTIFICATION = 5; // 0x5
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
-    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
-    field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
-    field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
-    field public static final int USAGE_UNKNOWN = 0; // 0x0
-    field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
-    field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
-  }
-
-  public static class AudioAttributesCompat.Builder {
-    ctor public AudioAttributesCompat.Builder();
-    ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat);
-    method public androidx.media.AudioAttributesCompat build();
-    method public androidx.media.AudioAttributesCompat.Builder setContentType(int);
-    method public androidx.media.AudioAttributesCompat.Builder setFlags(int);
-    method public androidx.media.AudioAttributesCompat.Builder setLegacyStreamType(int);
-    method public androidx.media.AudioAttributesCompat.Builder setUsage(int);
-  }
-
-  public abstract class MediaBrowserServiceCompat extends android.app.Service {
-    ctor public MediaBrowserServiceCompat();
-    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public final android.os.Bundle getBrowserRootHints();
-    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
-    method public void notifyChildrenChanged(java.lang.String);
-    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public void onCustomAction(java.lang.String, android.os.Bundle, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle>);
-    method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
-    method public abstract void onLoadChildren(java.lang.String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
-    method public void onLoadChildren(java.lang.String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>, android.os.Bundle);
-    method public void onLoadItem(java.lang.String, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem>);
-    method public void onSearch(java.lang.String, android.os.Bundle, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>>);
-    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
-  }
-
-  public static final class MediaBrowserServiceCompat.BrowserRoot {
-    ctor public MediaBrowserServiceCompat.BrowserRoot(java.lang.String, android.os.Bundle);
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getRootId();
-    field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-    field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
-    field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final deprecated java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
-  }
-
-  public static class MediaBrowserServiceCompat.Result<T> {
-    method public void detach();
-    method public void sendError(android.os.Bundle);
-    method public void sendProgressUpdate(android.os.Bundle);
-    method public void sendResult(T);
-  }
-
-  public abstract class VolumeProviderCompat {
-    ctor public VolumeProviderCompat(int, int, int);
-    method public final int getCurrentVolume();
-    method public final int getMaxVolume();
-    method public final int getVolumeControl();
-    method public java.lang.Object getVolumeProvider();
-    method public void onAdjustVolume(int);
-    method public void onSetVolumeTo(int);
-    method public void setCallback(androidx.media.VolumeProviderCompat.Callback);
-    method public final void setCurrentVolume(int);
-    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
-    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
-    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
-  }
-
-  public static abstract class VolumeProviderCompat.Callback {
-    ctor public VolumeProviderCompat.Callback();
-    method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat);
-  }
-
-}
-
-package androidx.media.app {
-
-  public class NotificationCompat {
-  }
-
-  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
-    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
-  }
-
-  public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
-    ctor public NotificationCompat.MediaStyle();
-    ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder);
-    method public static android.support.v4.media.session.MediaSessionCompat.Token getMediaSession(android.app.Notification);
-    method public androidx.media.app.NotificationCompat.MediaStyle setCancelButtonIntent(android.app.PendingIntent);
-    method public androidx.media.app.NotificationCompat.MediaStyle setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token);
-    method public androidx.media.app.NotificationCompat.MediaStyle setShowActionsInCompactView(int...);
-    method public androidx.media.app.NotificationCompat.MediaStyle setShowCancelButton(boolean);
-  }
-
-}
-
-package androidx.media.session {
-
-  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
-    ctor public MediaButtonReceiver();
-    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, long);
-    method public static android.app.PendingIntent buildMediaButtonPendingIntent(android.content.Context, android.content.ComponentName, long);
-    method public static android.view.KeyEvent handleIntent(android.support.v4.media.session.MediaSessionCompat, android.content.Intent);
-    method public void onReceive(android.content.Context, android.content.Intent);
-  }
-
-}
-
diff --git a/palette/palette/api/0.0.0.txt b/palette/palette/api/0.0.0.txt
deleted file mode 100644
index 04657c9..0000000
--- a/palette/palette/api/0.0.0.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-package androidx.palette.graphics {
-
-  public final class Palette {
-    method public static androidx.palette.graphics.Palette.Builder from(android.graphics.Bitmap);
-    method public static androidx.palette.graphics.Palette from(java.util.List<androidx.palette.graphics.Palette.Swatch>);
-    method public static deprecated androidx.palette.graphics.Palette generate(android.graphics.Bitmap);
-    method public static deprecated androidx.palette.graphics.Palette generate(android.graphics.Bitmap, int);
-    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, androidx.palette.graphics.Palette> generateAsync(android.graphics.Bitmap, androidx.palette.graphics.Palette.PaletteAsyncListener);
-    method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, androidx.palette.graphics.Palette> generateAsync(android.graphics.Bitmap, int, androidx.palette.graphics.Palette.PaletteAsyncListener);
-    method public int getColorForTarget(androidx.palette.graphics.Target, int);
-    method public int getDarkMutedColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getDarkMutedSwatch();
-    method public int getDarkVibrantColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getDarkVibrantSwatch();
-    method public int getDominantColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getDominantSwatch();
-    method public int getLightMutedColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getLightMutedSwatch();
-    method public int getLightVibrantColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getLightVibrantSwatch();
-    method public int getMutedColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getMutedSwatch();
-    method public androidx.palette.graphics.Palette.Swatch getSwatchForTarget(androidx.palette.graphics.Target);
-    method public java.util.List<androidx.palette.graphics.Palette.Swatch> getSwatches();
-    method public java.util.List<androidx.palette.graphics.Target> getTargets();
-    method public int getVibrantColor(int);
-    method public androidx.palette.graphics.Palette.Swatch getVibrantSwatch();
-  }
-
-  public static final class Palette.Builder {
-    ctor public Palette.Builder(android.graphics.Bitmap);
-    ctor public Palette.Builder(java.util.List<androidx.palette.graphics.Palette.Swatch>);
-    method public androidx.palette.graphics.Palette.Builder addFilter(androidx.palette.graphics.Palette.Filter);
-    method public androidx.palette.graphics.Palette.Builder addTarget(androidx.palette.graphics.Target);
-    method public androidx.palette.graphics.Palette.Builder clearFilters();
-    method public androidx.palette.graphics.Palette.Builder clearRegion();
-    method public androidx.palette.graphics.Palette.Builder clearTargets();
-    method public androidx.palette.graphics.Palette generate();
-    method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, androidx.palette.graphics.Palette> generate(androidx.palette.graphics.Palette.PaletteAsyncListener);
-    method public androidx.palette.graphics.Palette.Builder maximumColorCount(int);
-    method public androidx.palette.graphics.Palette.Builder resizeBitmapArea(int);
-    method public deprecated androidx.palette.graphics.Palette.Builder resizeBitmapSize(int);
-    method public androidx.palette.graphics.Palette.Builder setRegion(int, int, int, int);
-  }
-
-  public static abstract interface Palette.Filter {
-    method public abstract boolean isAllowed(int, float[]);
-  }
-
-  public static abstract interface Palette.PaletteAsyncListener {
-    method public abstract void onGenerated(androidx.palette.graphics.Palette);
-  }
-
-  public static final class Palette.Swatch {
-    ctor public Palette.Swatch(int, int);
-    method public int getBodyTextColor();
-    method public float[] getHsl();
-    method public int getPopulation();
-    method public int getRgb();
-    method public int getTitleTextColor();
-  }
-
-  public final class Target {
-    method public float getLightnessWeight();
-    method public float getMaximumLightness();
-    method public float getMaximumSaturation();
-    method public float getMinimumLightness();
-    method public float getMinimumSaturation();
-    method public float getPopulationWeight();
-    method public float getSaturationWeight();
-    method public float getTargetLightness();
-    method public float getTargetSaturation();
-    method public boolean isExclusive();
-    field public static final androidx.palette.graphics.Target DARK_MUTED;
-    field public static final androidx.palette.graphics.Target DARK_VIBRANT;
-    field public static final androidx.palette.graphics.Target LIGHT_MUTED;
-    field public static final androidx.palette.graphics.Target LIGHT_VIBRANT;
-    field public static final androidx.palette.graphics.Target MUTED;
-    field public static final androidx.palette.graphics.Target VIBRANT;
-  }
-
-  public static final class Target.Builder {
-    ctor public Target.Builder();
-    ctor public Target.Builder(androidx.palette.graphics.Target);
-    method public androidx.palette.graphics.Target build();
-    method public androidx.palette.graphics.Target.Builder setExclusive(boolean);
-    method public androidx.palette.graphics.Target.Builder setLightnessWeight(float);
-    method public androidx.palette.graphics.Target.Builder setMaximumLightness(float);
-    method public androidx.palette.graphics.Target.Builder setMaximumSaturation(float);
-    method public androidx.palette.graphics.Target.Builder setMinimumLightness(float);
-    method public androidx.palette.graphics.Target.Builder setMinimumSaturation(float);
-    method public androidx.palette.graphics.Target.Builder setPopulationWeight(float);
-    method public androidx.palette.graphics.Target.Builder setSaturationWeight(float);
-    method public androidx.palette.graphics.Target.Builder setTargetLightness(float);
-    method public androidx.palette.graphics.Target.Builder setTargetSaturation(float);
-  }
-
-}
-
diff --git a/preference/preference/api/0.0.0.txt b/preference/preference/api/0.0.0.txt
deleted file mode 100644
index 23dc5f8..0000000
--- a/preference/preference/api/0.0.0.txt
+++ /dev/null
@@ -1,508 +0,0 @@
-package androidx.preference {
-
-  public class EditTextPreferenceDialogFragment extends androidx.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static androidx.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends androidx.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static androidx.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends androidx.preference.DialogPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends androidx.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static androidx.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public androidx.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements androidx.preference.DialogPreference.TargetFragment androidx.preference.PreferenceManager.OnDisplayPreferenceDialogListener androidx.preference.PreferenceManager.OnNavigateToScreenListener androidx.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public androidx.preference.Preference findPreference(java.lang.CharSequence);
-    method public final androidx.recyclerview.widget.RecyclerView getListView();
-    method public androidx.preference.PreferenceManager getPreferenceManager();
-    method public androidx.preference.PreferenceScreen getPreferenceScreen();
-    method protected androidx.recyclerview.widget.RecyclerView.Adapter onCreateAdapter(androidx.preference.PreferenceScreen);
-    method public androidx.recyclerview.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public androidx.recyclerview.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(androidx.preference.Preference);
-    method public void onNavigateToScreen(androidx.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(androidx.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(androidx.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(androidx.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "androidx.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(androidx.preference.PreferenceFragment, androidx.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(androidx.preference.PreferenceFragment, androidx.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(androidx.preference.PreferenceFragment, androidx.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends androidx.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-  public class CheckBoxPreference extends androidx.preference.TwoStatePreference {
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
-    ctor public CheckBoxPreference(android.content.Context);
-  }
-
-  public abstract class DialogPreference extends androidx.preference.Preference {
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
-    ctor public DialogPreference(android.content.Context);
-    method public android.graphics.drawable.Drawable getDialogIcon();
-    method public int getDialogLayoutResource();
-    method public java.lang.CharSequence getDialogMessage();
-    method public java.lang.CharSequence getDialogTitle();
-    method public java.lang.CharSequence getNegativeButtonText();
-    method public java.lang.CharSequence getPositiveButtonText();
-    method public void setDialogIcon(android.graphics.drawable.Drawable);
-    method public void setDialogIcon(int);
-    method public void setDialogLayoutResource(int);
-    method public void setDialogMessage(java.lang.CharSequence);
-    method public void setDialogMessage(int);
-    method public void setDialogTitle(java.lang.CharSequence);
-    method public void setDialogTitle(int);
-    method public void setNegativeButtonText(java.lang.CharSequence);
-    method public void setNegativeButtonText(int);
-    method public void setPositiveButtonText(java.lang.CharSequence);
-    method public void setPositiveButtonText(int);
-  }
-
-  public static abstract interface DialogPreference.TargetFragment {
-    method public abstract androidx.preference.Preference findPreference(java.lang.CharSequence);
-  }
-
-  public class DropDownPreference extends androidx.preference.ListPreference {
-    ctor public DropDownPreference(android.content.Context);
-    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet);
-    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public DropDownPreference(android.content.Context, android.util.AttributeSet, int, int);
-    method protected android.widget.ArrayAdapter createAdapter();
-  }
-
-  public class EditTextPreference extends androidx.preference.DialogPreference {
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
-    ctor public EditTextPreference(android.content.Context);
-    method public java.lang.String getText();
-    method public void setText(java.lang.String);
-  }
-
-  public class EditTextPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
-    ctor public EditTextPreferenceDialogFragmentCompat();
-    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreference extends androidx.preference.DialogPreference {
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public ListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence getEntry();
-    method public java.lang.CharSequence[] getEntryValues();
-    method public java.lang.String getValue();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValue(java.lang.String);
-    method public void setValueIndex(int);
-  }
-
-  public class ListPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
-    ctor public ListPreferenceDialogFragmentCompat();
-    method public static androidx.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
-    ctor public MultiSelectListPreferenceDialogFragmentCompat();
-    method public static androidx.preference.MultiSelectListPreferenceDialogFragmentCompat newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class Preference implements java.lang.Comparable {
-    ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public Preference(android.content.Context, android.util.AttributeSet, int);
-    ctor public Preference(android.content.Context, android.util.AttributeSet);
-    ctor public Preference(android.content.Context);
-    method public boolean callChangeListener(java.lang.Object);
-    method public int compareTo(androidx.preference.Preference);
-    method protected androidx.preference.Preference findPreferenceInHierarchy(java.lang.String);
-    method public android.content.Context getContext();
-    method public java.lang.String getDependency();
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getFragment();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public android.content.Intent getIntent();
-    method public java.lang.String getKey();
-    method public final int getLayoutResource();
-    method public androidx.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
-    method public androidx.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
-    method public int getOrder();
-    method public androidx.preference.PreferenceGroup getParent();
-    method protected boolean getPersistedBoolean(boolean);
-    method protected float getPersistedFloat(float);
-    method protected int getPersistedInt(int);
-    method protected long getPersistedLong(long);
-    method protected java.lang.String getPersistedString(java.lang.String);
-    method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
-    method public androidx.preference.PreferenceDataStore getPreferenceDataStore();
-    method public androidx.preference.PreferenceManager getPreferenceManager();
-    method public android.content.SharedPreferences getSharedPreferences();
-    method public boolean getShouldDisableView();
-    method public java.lang.CharSequence getSummary();
-    method public java.lang.CharSequence getTitle();
-    method public final int getWidgetLayoutResource();
-    method public boolean hasKey();
-    method public boolean isEnabled();
-    method public boolean isIconSpaceReserved();
-    method public boolean isPersistent();
-    method public boolean isSelectable();
-    method public boolean isSingleLineTitle();
-    method public final boolean isVisible();
-    method protected void notifyChanged();
-    method public void notifyDependencyChange(boolean);
-    method protected void notifyHierarchyChanged();
-    method public void onAttached();
-    method protected void onAttachedToHierarchy(androidx.preference.PreferenceManager);
-    method public void onBindViewHolder(androidx.preference.PreferenceViewHolder);
-    method protected void onClick();
-    method public void onDependencyChanged(androidx.preference.Preference, boolean);
-    method public void onDetached();
-    method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
-    method public void onInitializeAccessibilityNodeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
-    method public void onParentChanged(androidx.preference.Preference, boolean);
-    method protected void onPrepareForRemoval();
-    method protected void onRestoreInstanceState(android.os.Parcelable);
-    method protected android.os.Parcelable onSaveInstanceState();
-    method protected void onSetInitialValue(boolean, java.lang.Object);
-    method public android.os.Bundle peekExtras();
-    method protected boolean persistBoolean(boolean);
-    method protected boolean persistFloat(float);
-    method protected boolean persistInt(int);
-    method protected boolean persistLong(long);
-    method protected boolean persistString(java.lang.String);
-    method public boolean persistStringSet(java.util.Set<java.lang.String>);
-    method public void restoreHierarchyState(android.os.Bundle);
-    method public void saveHierarchyState(android.os.Bundle);
-    method public void setDefaultValue(java.lang.Object);
-    method public void setDependency(java.lang.String);
-    method public void setEnabled(boolean);
-    method public void setFragment(java.lang.String);
-    method public void setIcon(android.graphics.drawable.Drawable);
-    method public void setIcon(int);
-    method public void setIconSpaceReserved(boolean);
-    method public void setIntent(android.content.Intent);
-    method public void setKey(java.lang.String);
-    method public void setLayoutResource(int);
-    method public void setOnPreferenceChangeListener(androidx.preference.Preference.OnPreferenceChangeListener);
-    method public void setOnPreferenceClickListener(androidx.preference.Preference.OnPreferenceClickListener);
-    method public void setOrder(int);
-    method public void setPersistent(boolean);
-    method public void setPreferenceDataStore(androidx.preference.PreferenceDataStore);
-    method public void setSelectable(boolean);
-    method public void setShouldDisableView(boolean);
-    method public void setSingleLineTitle(boolean);
-    method public void setSummary(java.lang.CharSequence);
-    method public void setSummary(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitle(int);
-    method public void setViewId(int);
-    method public final void setVisible(boolean);
-    method public void setWidgetLayoutResource(int);
-    method public boolean shouldDisableDependents();
-    method protected boolean shouldPersist();
-    field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
-  }
-
-  public static class Preference.BaseSavedState extends android.view.AbsSavedState {
-    ctor public Preference.BaseSavedState(android.os.Parcel);
-    ctor public Preference.BaseSavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<androidx.preference.Preference.BaseSavedState> CREATOR;
-  }
-
-  public static abstract interface Preference.OnPreferenceChangeListener {
-    method public abstract boolean onPreferenceChange(androidx.preference.Preference, java.lang.Object);
-  }
-
-  public static abstract interface Preference.OnPreferenceClickListener {
-    method public abstract boolean onPreferenceClick(androidx.preference.Preference);
-  }
-
-  public class PreferenceCategory extends androidx.preference.PreferenceGroup {
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
-    ctor public PreferenceCategory(android.content.Context);
-  }
-
-  public abstract class PreferenceDataStore {
-    ctor public PreferenceDataStore();
-    method public boolean getBoolean(java.lang.String, boolean);
-    method public float getFloat(java.lang.String, float);
-    method public int getInt(java.lang.String, int);
-    method public long getLong(java.lang.String, long);
-    method public java.lang.String getString(java.lang.String, java.lang.String);
-    method public java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
-    method public void putBoolean(java.lang.String, boolean);
-    method public void putFloat(java.lang.String, float);
-    method public void putInt(java.lang.String, int);
-    method public void putLong(java.lang.String, long);
-    method public void putString(java.lang.String, java.lang.String);
-    method public void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
-  }
-
-  public abstract class PreferenceDialogFragmentCompat extends androidx.fragment.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragmentCompat();
-    method public androidx.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(androidx.appcompat.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragmentCompat extends androidx.fragment.app.Fragment implements androidx.preference.DialogPreference.TargetFragment androidx.preference.PreferenceManager.OnDisplayPreferenceDialogListener androidx.preference.PreferenceManager.OnNavigateToScreenListener androidx.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragmentCompat();
-    method public void addPreferencesFromResource(int);
-    method public androidx.preference.Preference findPreference(java.lang.CharSequence);
-    method public final androidx.recyclerview.widget.RecyclerView getListView();
-    method public androidx.preference.PreferenceManager getPreferenceManager();
-    method public androidx.preference.PreferenceScreen getPreferenceScreen();
-    method protected androidx.recyclerview.widget.RecyclerView.Adapter onCreateAdapter(androidx.preference.PreferenceScreen);
-    method public androidx.recyclerview.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public androidx.recyclerview.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(androidx.preference.Preference);
-    method public void onNavigateToScreen(androidx.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(androidx.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(androidx.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(androidx.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "androidx.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(androidx.preference.PreferenceFragmentCompat, androidx.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(androidx.preference.PreferenceFragmentCompat, androidx.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(androidx.preference.PreferenceFragmentCompat, androidx.preference.PreferenceScreen);
-  }
-
-  public abstract class PreferenceGroup extends androidx.preference.Preference {
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
-    method public void addItemFromInflater(androidx.preference.Preference);
-    method public boolean addPreference(androidx.preference.Preference);
-    method protected void dispatchRestoreInstanceState(android.os.Bundle);
-    method protected void dispatchSaveInstanceState(android.os.Bundle);
-    method public androidx.preference.Preference findPreference(java.lang.CharSequence);
-    method public int getInitialExpandedChildrenCount();
-    method public androidx.preference.Preference getPreference(int);
-    method public int getPreferenceCount();
-    method protected boolean isOnSameScreenAsChildren();
-    method public boolean isOrderingAsAdded();
-    method protected boolean onPrepareAddPreference(androidx.preference.Preference);
-    method public void removeAll();
-    method public boolean removePreference(androidx.preference.Preference);
-    method public void setInitialExpandedChildrenCount(int);
-    method public void setOrderingAsAdded(boolean);
-  }
-
-  public static abstract interface PreferenceGroup.PreferencePositionCallback {
-    method public abstract int getPreferenceAdapterPosition(java.lang.String);
-    method public abstract int getPreferenceAdapterPosition(androidx.preference.Preference);
-  }
-
-  public class PreferenceManager {
-    method public androidx.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
-    method public androidx.preference.Preference findPreference(java.lang.CharSequence);
-    method public android.content.Context getContext();
-    method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
-    method public androidx.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
-    method public androidx.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
-    method public androidx.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
-    method public androidx.preference.PreferenceManager.PreferenceComparisonCallback getPreferenceComparisonCallback();
-    method public androidx.preference.PreferenceDataStore getPreferenceDataStore();
-    method public androidx.preference.PreferenceScreen getPreferenceScreen();
-    method public android.content.SharedPreferences getSharedPreferences();
-    method public int getSharedPreferencesMode();
-    method public java.lang.String getSharedPreferencesName();
-    method public boolean isStorageDefault();
-    method public boolean isStorageDeviceProtected();
-    method public static void setDefaultValues(android.content.Context, int, boolean);
-    method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
-    method public void setOnDisplayPreferenceDialogListener(androidx.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
-    method public void setOnNavigateToScreenListener(androidx.preference.PreferenceManager.OnNavigateToScreenListener);
-    method public void setOnPreferenceTreeClickListener(androidx.preference.PreferenceManager.OnPreferenceTreeClickListener);
-    method public void setPreferenceComparisonCallback(androidx.preference.PreferenceManager.PreferenceComparisonCallback);
-    method public void setPreferenceDataStore(androidx.preference.PreferenceDataStore);
-    method public boolean setPreferences(androidx.preference.PreferenceScreen);
-    method public void setSharedPreferencesMode(int);
-    method public void setSharedPreferencesName(java.lang.String);
-    method public void setStorageDefault();
-    method public void setStorageDeviceProtected();
-    method public void showDialog(androidx.preference.Preference);
-    field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
-  }
-
-  public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
-    method public abstract void onDisplayPreferenceDialog(androidx.preference.Preference);
-  }
-
-  public static abstract interface PreferenceManager.OnNavigateToScreenListener {
-    method public abstract void onNavigateToScreen(androidx.preference.PreferenceScreen);
-  }
-
-  public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
-    method public abstract boolean onPreferenceTreeClick(androidx.preference.Preference);
-  }
-
-  public static abstract class PreferenceManager.PreferenceComparisonCallback {
-    ctor public PreferenceManager.PreferenceComparisonCallback();
-    method public abstract boolean arePreferenceContentsTheSame(androidx.preference.Preference, androidx.preference.Preference);
-    method public abstract boolean arePreferenceItemsTheSame(androidx.preference.Preference, androidx.preference.Preference);
-  }
-
-  public static class PreferenceManager.SimplePreferenceComparisonCallback extends androidx.preference.PreferenceManager.PreferenceComparisonCallback {
-    ctor public PreferenceManager.SimplePreferenceComparisonCallback();
-    method public boolean arePreferenceContentsTheSame(androidx.preference.Preference, androidx.preference.Preference);
-    method public boolean arePreferenceItemsTheSame(androidx.preference.Preference, androidx.preference.Preference);
-  }
-
-  public final class PreferenceScreen extends androidx.preference.PreferenceGroup {
-    method public void setShouldUseGeneratedIds(boolean);
-    method public boolean shouldUseGeneratedIds();
-  }
-
-  public class PreferenceViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder {
-    method public android.view.View findViewById(int);
-    method public boolean isDividerAllowedAbove();
-    method public boolean isDividerAllowedBelow();
-    method public void setDividerAllowedAbove(boolean);
-    method public void setDividerAllowedBelow(boolean);
-  }
-
-  public class SeekBarPreference extends androidx.preference.Preference {
-    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SeekBarPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SeekBarPreference(android.content.Context);
-    method public int getMax();
-    method public int getMin();
-    method public final int getSeekBarIncrement();
-    method public int getValue();
-    method public boolean isAdjustable();
-    method public void setAdjustable(boolean);
-    method public final void setMax(int);
-    method public void setMin(int);
-    method public final void setSeekBarIncrement(int);
-    method public void setValue(int);
-  }
-
-  public class SwitchPreferenceCompat extends androidx.preference.TwoStatePreference {
-    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreferenceCompat(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-  public abstract class TwoStatePreference extends androidx.preference.Preference {
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
-    ctor public TwoStatePreference(android.content.Context);
-    method public boolean getDisableDependentsState();
-    method public java.lang.CharSequence getSummaryOff();
-    method public java.lang.CharSequence getSummaryOn();
-    method public boolean isChecked();
-    method public void setChecked(boolean);
-    method public void setDisableDependentsState(boolean);
-    method public void setSummaryOff(java.lang.CharSequence);
-    method public void setSummaryOff(int);
-    method public void setSummaryOn(java.lang.CharSequence);
-    method public void setSummaryOn(int);
-    method protected void syncSummaryView(androidx.preference.PreferenceViewHolder);
-    field protected boolean mChecked;
-  }
-
-}
-
diff --git a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/FrameworkAidlInputs.kt b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/FrameworkAidlInputs.kt
index 6aa4333..4f9dfbf 100644
--- a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/FrameworkAidlInputs.kt
+++ b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/FrameworkAidlInputs.kt
@@ -37,6 +37,6 @@
         if (!frameworkAidlFile.exists()) {
             throw FileNotFoundException("framework.aidl not found at $frameworkAidlPath")
         }
-        return listOf("framework_aidl=$frameworkAidlPath")
+        return listOf("framework_aidl_path=$frameworkAidlPath")
     }
 }
\ No newline at end of file
diff --git a/privacysandbox/plugins/plugins-privacysandbox-library/src/test/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPluginTest.kt b/privacysandbox/plugins/plugins-privacysandbox-library/src/test/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPluginTest.kt
index ac1f28b..fe72161 100644
--- a/privacysandbox/plugins/plugins-privacysandbox-library/src/test/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPluginTest.kt
+++ b/privacysandbox/plugins/plugins-privacysandbox-library/src/test/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPluginTest.kt
@@ -39,9 +39,6 @@
 
     @Before
     fun setUp() {
-        File("src/test/test-data", "app-project")
-            .also { it.mkdirs() }
-            .copyRecursively(projectSetup.rootDir)
         File(projectSetup.rootDir, "settings.gradle")
             .writeText("rootProject.name = \"test-privacysandbox-library\"")
         projectSetup.writeDefaultBuildGradle(
diff --git a/privacysandbox/ui/integration-tests/testapp/build.gradle b/privacysandbox/ui/integration-tests/testapp/build.gradle
index f4f03c6..518a00a 100644
--- a/privacysandbox/ui/integration-tests/testapp/build.gradle
+++ b/privacysandbox/ui/integration-tests/testapp/build.gradle
@@ -55,7 +55,9 @@
     implementation 'androidx.core:core-ktx:1.8.0'
     implementation 'androidx.appcompat:appcompat:1.6.0'
     implementation 'com.google.android.material:material:1.6.0'
+    implementation "androidx.activity:activity-ktx:1.7.2"
     implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
+    implementation "androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha03"
     implementation project(':privacysandbox:ui:integration-tests:testaidl')
     implementation project(':privacysandbox:ui:ui-core')
     implementation project(':privacysandbox:ui:ui-client')
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 9373477..09afb2d 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
@@ -16,12 +16,8 @@
 
 package androidx.privacysandbox.ui.integration.testapp
 
-import android.app.sdksandbox.LoadSdkException
-import android.app.sdksandbox.SandboxedSdk
-import android.app.sdksandbox.SdkSandboxManager
 import android.content.res.Configuration
 import android.os.Bundle
-import android.os.OutcomeReceiver
 import android.os.ext.SdkExtensions
 import android.util.Log
 import android.view.ViewGroup
@@ -29,16 +25,20 @@
 import android.widget.TextView
 import androidx.annotation.RequiresExtension
 import androidx.appcompat.app.AppCompatActivity
+import androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
 import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
 import androidx.privacysandbox.ui.client.view.SandboxedSdkUiSessionState
 import androidx.privacysandbox.ui.client.view.SandboxedSdkUiSessionStateChangedListener
 import androidx.privacysandbox.ui.client.view.SandboxedSdkView
 import androidx.privacysandbox.ui.integration.testaidl.ISdkApi
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
 
 class MainActivity : AppCompatActivity() {
-    private lateinit var mSdkSandboxManager: SdkSandboxManager
-
-    private lateinit var mSandboxedSdk: SandboxedSdk
+    private lateinit var mSdkSandboxManager: SdkSandboxManagerCompat
 
     private var mSdkLoaded = false
 
@@ -51,55 +51,47 @@
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
 
-        mSdkSandboxManager = applicationContext.getSystemService(
-            SdkSandboxManager::class.java
-        )
+        mSdkSandboxManager = SdkSandboxManagerCompat.from(applicationContext)
 
         if (!mSdkLoaded) {
             Log.i(TAG, "Loading SDK")
-            mSdkSandboxManager.loadSdk(
-                SDK_NAME, Bundle(), { obj: Runnable -> obj.run() }, LoadSdkCallbackImpl()
-            )
+            CoroutineScope(Dispatchers.Default).launch {
+                try {
+                    val loadedSdk = mSdkSandboxManager.loadSdk(SDK_NAME, Bundle())
+                    onLoadedSdk(loadedSdk)
+                } catch (e: LoadSdkCompatException) {
+                    Log.i(TAG, "loadSdk failed with errorCode: " + e.loadSdkErrorCode +
+                        " and errorMsg: " + e.message)
+                }
+            }
         }
     }
+    private fun onLoadedSdk(sandboxedSdk: SandboxedSdkCompat) {
+        Log.i(TAG, "Loaded successfully")
+        mSdkLoaded = true
+        val sdkApi = ISdkApi.Stub.asInterface(sandboxedSdk.getInterface())
+
+        mSandboxedSdkView1 = findViewById<SandboxedSdkView>(R.id.rendered_view)
+        mSandboxedSdkView1.addStateChangedListener(StateChangeListener(mSandboxedSdkView1))
+        mSandboxedSdkView1.setAdapter(SandboxedUiAdapterFactory.createFromCoreLibInfo(
+            sdkApi.loadAd(/*isWebView=*/ true)
+        ))
+
+        mSandboxedSdkView2 = SandboxedSdkView(this@MainActivity)
+        mSandboxedSdkView2.addStateChangedListener(StateChangeListener(mSandboxedSdkView2))
+        mSandboxedSdkView2.layoutParams = ViewGroup.LayoutParams(200, 200)
+        runOnUiThread(Runnable {
+            findViewById<LinearLayout>(R.id.ad_layout).addView(mSandboxedSdkView2)
+        })
+        mSandboxedSdkView2.setAdapter(SandboxedUiAdapterFactory.createFromCoreLibInfo(
+            sdkApi.loadAd(/*isWebView=*/ false)
+        ))
+    }
 
     override fun onConfigurationChanged(newConfig: Configuration) {
         super.onConfigurationChanged(newConfig)
     }
 
-    // TODO(b/257429573): Remove this line once fixed.
-    @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
-    private inner class LoadSdkCallbackImpl() : OutcomeReceiver<SandboxedSdk, LoadSdkException> {
-
-        override fun onResult(sandboxedSdk: SandboxedSdk) {
-            Log.i(TAG, "Loaded successfully")
-            mSandboxedSdk = sandboxedSdk
-            mSdkLoaded = true
-            val sdkApi = ISdkApi.Stub.asInterface(mSandboxedSdk.getInterface())
-
-            mSandboxedSdkView1 = findViewById<SandboxedSdkView>(R.id.rendered_view)
-            mSandboxedSdkView1.addStateChangedListener(StateChangeListener(mSandboxedSdkView1))
-            mSandboxedSdkView1.setAdapter(SandboxedUiAdapterFactory.createFromCoreLibInfo(
-                sdkApi.loadAd(/*isWebView=*/ true)
-            ))
-
-            mSandboxedSdkView2 = SandboxedSdkView(this@MainActivity)
-            mSandboxedSdkView2.addStateChangedListener(StateChangeListener(mSandboxedSdkView2))
-            mSandboxedSdkView2.layoutParams = ViewGroup.LayoutParams(200, 200)
-            runOnUiThread(Runnable {
-                findViewById<LinearLayout>(R.id.ad_layout).addView(mSandboxedSdkView2)
-            })
-            mSandboxedSdkView2.setAdapter(SandboxedUiAdapterFactory.createFromCoreLibInfo(
-                sdkApi.loadAd(/*isWebView=*/ false)
-            ))
-        }
-
-        override fun onError(error: LoadSdkException) {
-            Log.i(TAG, "onLoadSdkFailure(" + error.getLoadSdkErrorCode().toString() + "): " +
-                error.message)
-        }
-    }
-
     private inner class StateChangeListener(val view: SandboxedSdkView) :
         SandboxedSdkUiSessionStateChangedListener {
         override fun onStateChanged(state: SandboxedSdkUiSessionState) {
diff --git a/recyclerview/recyclerview/api/0.0.0.txt b/recyclerview/recyclerview/api/0.0.0.txt
deleted file mode 100644
index 83560f8..0000000
--- a/recyclerview/recyclerview/api/0.0.0.txt
+++ /dev/null
@@ -1,1014 +0,0 @@
-package androidx.recyclerview.widget {
-
-  public final class AsyncDifferConfig<T> {
-    method public java.util.concurrent.Executor getBackgroundThreadExecutor();
-    method public androidx.recyclerview.widget.DiffUtil.ItemCallback<T> getDiffCallback();
-  }
-
-  public static final class AsyncDifferConfig.Builder<T> {
-    ctor public AsyncDifferConfig.Builder(androidx.recyclerview.widget.DiffUtil.ItemCallback<T>);
-    method public androidx.recyclerview.widget.AsyncDifferConfig<T> build();
-    method public androidx.recyclerview.widget.AsyncDifferConfig.Builder<T> setBackgroundThreadExecutor(java.util.concurrent.Executor);
-  }
-
-  public class AsyncListDiffer<T> {
-    ctor public AsyncListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T>);
-    ctor public AsyncListDiffer(androidx.recyclerview.widget.ListUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T>);
-    method public java.util.List<T> getCurrentList();
-    method public void submitList(java.util.List<T>);
-  }
-
-  public abstract class ListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter {
-    ctor protected ListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T>);
-    ctor protected ListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T>);
-    method protected T getItem(int);
-    method public int getItemCount();
-    method public void submitList(java.util.List<T>);
-  }
-
-  public final class AdapterListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
-    ctor public AdapterListUpdateCallback(androidx.recyclerview.widget.RecyclerView.Adapter);
-    method public void onChanged(int, int, java.lang.Object);
-    method public void onInserted(int, int);
-    method public void onMoved(int, int);
-    method public void onRemoved(int, int);
-  }
-
-  public class AsyncListUtil<T> {
-    ctor public AsyncListUtil(java.lang.Class<T>, int, androidx.recyclerview.widget.AsyncListUtil.DataCallback<T>, androidx.recyclerview.widget.AsyncListUtil.ViewCallback);
-    method public T getItem(int);
-    method public int getItemCount();
-    method public void onRangeChanged();
-    method public void refresh();
-  }
-
-  public static abstract class AsyncListUtil.DataCallback<T> {
-    ctor public AsyncListUtil.DataCallback();
-    method public abstract void fillData(T[], int, int);
-    method public int getMaxCachedTiles();
-    method public void recycleData(T[], int);
-    method public abstract int refreshData();
-  }
-
-  public static abstract class AsyncListUtil.ViewCallback {
-    ctor public AsyncListUtil.ViewCallback();
-    method public void extendRangeInto(int[], int[], int);
-    method public abstract void getItemRangeInto(int[]);
-    method public abstract void onDataRefresh();
-    method public abstract void onItemLoaded(int);
-    field public static final int HINT_SCROLL_ASC = 2; // 0x2
-    field public static final int HINT_SCROLL_DESC = 1; // 0x1
-    field public static final int HINT_SCROLL_NONE = 0; // 0x0
-  }
-
-  public class BatchingListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
-    ctor public BatchingListUpdateCallback(androidx.recyclerview.widget.ListUpdateCallback);
-    method public void dispatchLastEvent();
-    method public void onChanged(int, int, java.lang.Object);
-    method public void onInserted(int, int);
-    method public void onMoved(int, int);
-    method public void onRemoved(int, int);
-  }
-
-  public class DiffUtil {
-    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback);
-    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback, boolean);
-  }
-
-  public static abstract class DiffUtil.Callback {
-    ctor public DiffUtil.Callback();
-    method public abstract boolean areContentsTheSame(int, int);
-    method public abstract boolean areItemsTheSame(int, int);
-    method public java.lang.Object getChangePayload(int, int);
-    method public abstract int getNewListSize();
-    method public abstract int getOldListSize();
-  }
-
-  public static class DiffUtil.DiffResult {
-    method public void dispatchUpdatesTo(androidx.recyclerview.widget.RecyclerView.Adapter);
-    method public void dispatchUpdatesTo(androidx.recyclerview.widget.ListUpdateCallback);
-  }
-
-  public static abstract class DiffUtil.ItemCallback<T> {
-    ctor public DiffUtil.ItemCallback();
-    method public abstract boolean areContentsTheSame(T, T);
-    method public abstract boolean areItemsTheSame(T, T);
-    method public java.lang.Object getChangePayload(T, T);
-  }
-
-  public abstract interface ListUpdateCallback {
-    method public abstract void onChanged(int, int, java.lang.Object);
-    method public abstract void onInserted(int, int);
-    method public abstract void onMoved(int, int);
-    method public abstract void onRemoved(int, int);
-  }
-
-  public class SortedList<T> {
-    ctor public SortedList(java.lang.Class<T>, androidx.recyclerview.widget.SortedList.Callback<T>);
-    ctor public SortedList(java.lang.Class<T>, androidx.recyclerview.widget.SortedList.Callback<T>, int);
-    method public int add(T);
-    method public void addAll(T[], boolean);
-    method public void addAll(T...);
-    method public void addAll(java.util.Collection<T>);
-    method public void beginBatchedUpdates();
-    method public void clear();
-    method public void endBatchedUpdates();
-    method public T get(int) throws java.lang.IndexOutOfBoundsException;
-    method public int indexOf(T);
-    method public void recalculatePositionOfItemAt(int);
-    method public boolean remove(T);
-    method public T removeItemAt(int);
-    method public void replaceAll(T[], boolean);
-    method public void replaceAll(T...);
-    method public void replaceAll(java.util.Collection<T>);
-    method public int size();
-    method public void updateItemAt(int, T);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static class SortedList.BatchedCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback {
-    ctor public SortedList.BatchedCallback(androidx.recyclerview.widget.SortedList.Callback<T2>);
-    method public boolean areContentsTheSame(T2, T2);
-    method public boolean areItemsTheSame(T2, T2);
-    method public int compare(T2, T2);
-    method public void dispatchLastEvent();
-    method public void onChanged(int, int);
-    method public void onInserted(int, int);
-    method public void onMoved(int, int);
-    method public void onRemoved(int, int);
-  }
-
-  public static abstract class SortedList.Callback<T2> implements java.util.Comparator androidx.recyclerview.widget.ListUpdateCallback {
-    ctor public SortedList.Callback();
-    method public abstract boolean areContentsTheSame(T2, T2);
-    method public abstract boolean areItemsTheSame(T2, T2);
-    method public abstract int compare(T2, T2);
-    method public java.lang.Object getChangePayload(T2, T2);
-    method public abstract void onChanged(int, int);
-    method public void onChanged(int, int, java.lang.Object);
-  }
-
-  public class DefaultItemAnimator extends androidx.recyclerview.widget.SimpleItemAnimator {
-    ctor public DefaultItemAnimator();
-    method public boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void endAnimations();
-    method public boolean isRunning();
-    method public void runPendingAnimations();
-  }
-
-  public class DividerItemDecoration extends androidx.recyclerview.widget.RecyclerView.ItemDecoration {
-    ctor public DividerItemDecoration(android.content.Context, int);
-    method public void setDrawable(android.graphics.drawable.Drawable);
-    method public void setOrientation(int);
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int VERTICAL = 1; // 0x1
-  }
-
-  public class GridLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
-    ctor public GridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public GridLayoutManager(android.content.Context, int);
-    ctor public GridLayoutManager(android.content.Context, int, int, boolean);
-    method public int getSpanCount();
-    method public androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup getSpanSizeLookup();
-    method public void setSpanCount(int);
-    method public void setSpanSizeLookup(androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup);
-    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
-  }
-
-  public static final class GridLayoutManager.DefaultSpanSizeLookup extends androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup {
-    ctor public GridLayoutManager.DefaultSpanSizeLookup();
-    method public int getSpanSize(int);
-  }
-
-  public static class GridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
-    ctor public GridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public GridLayoutManager.LayoutParams(int, int);
-    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public GridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams);
-    method public int getSpanIndex();
-    method public int getSpanSize();
-    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
-  }
-
-  public static abstract class GridLayoutManager.SpanSizeLookup {
-    ctor public GridLayoutManager.SpanSizeLookup();
-    method public int getSpanGroupIndex(int, int);
-    method public int getSpanIndex(int, int);
-    method public abstract int getSpanSize(int);
-    method public void invalidateSpanIndexCache();
-    method public boolean isSpanIndexCacheEnabled();
-    method public void setSpanIndexCacheEnabled(boolean);
-  }
-
-  public class LinearLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.ItemTouchHelper.ViewDropHandler androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
-    ctor public LinearLayoutManager(android.content.Context);
-    ctor public LinearLayoutManager(android.content.Context, int, boolean);
-    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
-    method public android.graphics.PointF computeScrollVectorForPosition(int);
-    method public int findFirstCompletelyVisibleItemPosition();
-    method public int findFirstVisibleItemPosition();
-    method public int findLastCompletelyVisibleItemPosition();
-    method public int findLastVisibleItemPosition();
-    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
-    method protected int getExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State);
-    method public int getInitialPrefetchItemCount();
-    method public int getOrientation();
-    method public boolean getRecycleChildrenOnDetach();
-    method public boolean getReverseLayout();
-    method public boolean getStackFromEnd();
-    method protected boolean isLayoutRTL();
-    method public boolean isSmoothScrollbarEnabled();
-    method public void prepareForDrop(android.view.View, android.view.View, int, int);
-    method public void scrollToPositionWithOffset(int, int);
-    method public void setInitialPrefetchItemCount(int);
-    method public void setOrientation(int);
-    method public void setRecycleChildrenOnDetach(boolean);
-    method public void setReverseLayout(boolean);
-    method public void setSmoothScrollbarEnabled(boolean);
-    method public void setStackFromEnd(boolean);
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
-    field public static final int VERTICAL = 1; // 0x1
-  }
-
-  protected static class LinearLayoutManager.LayoutChunkResult {
-    ctor protected LinearLayoutManager.LayoutChunkResult();
-    field public int mConsumed;
-    field public boolean mFinished;
-    field public boolean mFocusable;
-    field public boolean mIgnoreConsumed;
-  }
-
-  public class LinearSmoothScroller extends androidx.recyclerview.widget.RecyclerView.SmoothScroller {
-    ctor public LinearSmoothScroller(android.content.Context);
-    method public int calculateDtToFit(int, int, int, int, int);
-    method public int calculateDxToMakeVisible(android.view.View, int);
-    method public int calculateDyToMakeVisible(android.view.View, int);
-    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
-    method protected int calculateTimeForDeceleration(int);
-    method protected int calculateTimeForScrolling(int);
-    method public android.graphics.PointF computeScrollVectorForPosition(int);
-    method protected int getHorizontalSnapPreference();
-    method protected int getVerticalSnapPreference();
-    method protected void onSeekTargetStep(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
-    method protected void onStart();
-    method protected void onStop();
-    method protected void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
-    method protected void updateActionForInterimTarget(androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
-    field public static final int SNAP_TO_ANY = 0; // 0x0
-    field public static final int SNAP_TO_END = 1; // 0x1
-    field public static final int SNAP_TO_START = -1; // 0xffffffff
-    field protected final android.view.animation.DecelerateInterpolator mDecelerateInterpolator;
-    field protected int mInterimTargetDx;
-    field protected int mInterimTargetDy;
-    field protected final android.view.animation.LinearInterpolator mLinearInterpolator;
-    field protected android.graphics.PointF mTargetVector;
-  }
-
-  public class LinearSnapHelper extends androidx.recyclerview.widget.SnapHelper {
-    ctor public LinearSnapHelper();
-    method public int[] calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
-    method public android.view.View findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
-  }
-
-  public abstract class OrientationHelper {
-    method public static androidx.recyclerview.widget.OrientationHelper createHorizontalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public static androidx.recyclerview.widget.OrientationHelper createOrientationHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager, int);
-    method public static androidx.recyclerview.widget.OrientationHelper createVerticalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public abstract int getDecoratedEnd(android.view.View);
-    method public abstract int getDecoratedMeasurement(android.view.View);
-    method public abstract int getDecoratedMeasurementInOther(android.view.View);
-    method public abstract int getDecoratedStart(android.view.View);
-    method public abstract int getEnd();
-    method public abstract int getEndAfterPadding();
-    method public abstract int getEndPadding();
-    method public androidx.recyclerview.widget.RecyclerView.LayoutManager getLayoutManager();
-    method public abstract int getMode();
-    method public abstract int getModeInOther();
-    method public abstract int getStartAfterPadding();
-    method public abstract int getTotalSpace();
-    method public int getTotalSpaceChange();
-    method public abstract int getTransformedEndWithDecoration(android.view.View);
-    method public abstract int getTransformedStartWithDecoration(android.view.View);
-    method public abstract void offsetChild(android.view.View, int);
-    method public abstract void offsetChildren(int);
-    method public void onLayoutComplete();
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int VERTICAL = 1; // 0x1
-    field protected final androidx.recyclerview.widget.RecyclerView.LayoutManager mLayoutManager;
-  }
-
-  public class PagerSnapHelper extends androidx.recyclerview.widget.SnapHelper {
-    ctor public PagerSnapHelper();
-    method public int[] calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
-    method protected androidx.recyclerview.widget.LinearSmoothScroller createSnapScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public android.view.View findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
-  }
-
-  public class RecyclerView extends android.view.ViewGroup implements androidx.core.view.NestedScrollingChild2 androidx.core.view.ScrollingView {
-    ctor public RecyclerView(android.content.Context);
-    ctor public RecyclerView(android.content.Context, android.util.AttributeSet);
-    ctor public RecyclerView(android.content.Context, android.util.AttributeSet, int);
-    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
-    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
-    method public void addOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
-    method public void addOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
-    method public void addOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
-    method public void clearOnChildAttachStateChangeListeners();
-    method public void clearOnScrollListeners();
-    method public int computeHorizontalScrollExtent();
-    method public int computeHorizontalScrollOffset();
-    method public int computeHorizontalScrollRange();
-    method public int computeVerticalScrollExtent();
-    method public int computeVerticalScrollOffset();
-    method public int computeVerticalScrollRange();
-    method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
-    method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
-    method public boolean drawChild(android.graphics.Canvas, android.view.View, long);
-    method public android.view.View findChildViewUnder(float, float);
-    method public android.view.View findContainingItemView(android.view.View);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder findContainingViewHolder(android.view.View);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder findViewHolderForAdapterPosition(int);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder findViewHolderForItemId(long);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder findViewHolderForLayoutPosition(int);
-    method public deprecated androidx.recyclerview.widget.RecyclerView.ViewHolder findViewHolderForPosition(int);
-    method public boolean fling(int, int);
-    method public androidx.recyclerview.widget.RecyclerView.Adapter getAdapter();
-    method public int getChildAdapterPosition(android.view.View);
-    method public long getChildItemId(android.view.View);
-    method public int getChildLayoutPosition(android.view.View);
-    method public deprecated int getChildPosition(android.view.View);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder getChildViewHolder(android.view.View);
-    method public androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate();
-    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
-    method public androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory getEdgeEffectFactory();
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator getItemAnimator();
-    method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
-    method public int getItemDecorationCount();
-    method public androidx.recyclerview.widget.RecyclerView.LayoutManager getLayoutManager();
-    method public int getMaxFlingVelocity();
-    method public int getMinFlingVelocity();
-    method public androidx.recyclerview.widget.RecyclerView.OnFlingListener getOnFlingListener();
-    method public boolean getPreserveFocusAfterLayout();
-    method public androidx.recyclerview.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
-    method public int getScrollState();
-    method public boolean hasFixedSize();
-    method public boolean hasNestedScrollingParent(int);
-    method public boolean hasPendingAdapterUpdates();
-    method public void invalidateItemDecorations();
-    method public boolean isAnimating();
-    method public boolean isComputingLayout();
-    method public boolean isLayoutFrozen();
-    method public void offsetChildrenHorizontal(int);
-    method public void offsetChildrenVertical(int);
-    method public void onChildAttachedToWindow(android.view.View);
-    method public void onChildDetachedFromWindow(android.view.View);
-    method public void onDraw(android.graphics.Canvas);
-    method public void onScrollStateChanged(int);
-    method public void onScrolled(int, int);
-    method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
-    method public void removeItemDecorationAt(int);
-    method public void removeOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
-    method public void removeOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
-    method public void removeOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
-    method public void scrollToPosition(int);
-    method public void setAccessibilityDelegateCompat(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate);
-    method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter);
-    method public void setChildDrawingOrderCallback(androidx.recyclerview.widget.RecyclerView.ChildDrawingOrderCallback);
-    method public void setEdgeEffectFactory(androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory);
-    method public void setHasFixedSize(boolean);
-    method public void setItemAnimator(androidx.recyclerview.widget.RecyclerView.ItemAnimator);
-    method public void setItemViewCacheSize(int);
-    method public void setLayoutFrozen(boolean);
-    method public void setLayoutManager(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public void setOnFlingListener(androidx.recyclerview.widget.RecyclerView.OnFlingListener);
-    method public deprecated void setOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
-    method public void setPreserveFocusAfterLayout(boolean);
-    method public void setRecycledViewPool(androidx.recyclerview.widget.RecyclerView.RecycledViewPool);
-    method public void setRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
-    method public void setScrollingTouchSlop(int);
-    method public void setViewCacheExtension(androidx.recyclerview.widget.RecyclerView.ViewCacheExtension);
-    method public void smoothScrollBy(int, int);
-    method public void smoothScrollBy(int, int, android.view.animation.Interpolator);
-    method public void smoothScrollToPosition(int);
-    method public boolean startNestedScroll(int, int);
-    method public void stopNestedScroll(int);
-    method public void stopScroll();
-    method public void swapAdapter(androidx.recyclerview.widget.RecyclerView.Adapter, boolean);
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int INVALID_TYPE = -1; // 0xffffffff
-    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
-    field public static final int NO_POSITION = -1; // 0xffffffff
-    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
-    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
-    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
-    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
-    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
-    field public static final int VERTICAL = 1; // 0x1
-  }
-
-  public static abstract class RecyclerView.Adapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> {
-    ctor public RecyclerView.Adapter();
-    method public final void bindViewHolder(VH, int);
-    method public final VH createViewHolder(android.view.ViewGroup, int);
-    method public abstract int getItemCount();
-    method public long getItemId(int);
-    method public int getItemViewType(int);
-    method public final boolean hasObservers();
-    method public final boolean hasStableIds();
-    method public final void notifyDataSetChanged();
-    method public final void notifyItemChanged(int);
-    method public final void notifyItemChanged(int, java.lang.Object);
-    method public final void notifyItemInserted(int);
-    method public final void notifyItemMoved(int, int);
-    method public final void notifyItemRangeChanged(int, int);
-    method public final void notifyItemRangeChanged(int, int, java.lang.Object);
-    method public final void notifyItemRangeInserted(int, int);
-    method public final void notifyItemRangeRemoved(int, int);
-    method public final void notifyItemRemoved(int);
-    method public void onAttachedToRecyclerView(androidx.recyclerview.widget.RecyclerView);
-    method public abstract void onBindViewHolder(VH, int);
-    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object>);
-    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
-    method public void onDetachedFromRecyclerView(androidx.recyclerview.widget.RecyclerView);
-    method public boolean onFailedToRecycleView(VH);
-    method public void onViewAttachedToWindow(VH);
-    method public void onViewDetachedFromWindow(VH);
-    method public void onViewRecycled(VH);
-    method public void registerAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
-    method public void setHasStableIds(boolean);
-    method public void unregisterAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
-  }
-
-  public static abstract class RecyclerView.AdapterDataObserver {
-    ctor public RecyclerView.AdapterDataObserver();
-    method public void onChanged();
-    method public void onItemRangeChanged(int, int);
-    method public void onItemRangeChanged(int, int, java.lang.Object);
-    method public void onItemRangeInserted(int, int);
-    method public void onItemRangeMoved(int, int, int);
-    method public void onItemRangeRemoved(int, int);
-  }
-
-  public static abstract interface RecyclerView.ChildDrawingOrderCallback {
-    method public abstract int onGetChildDrawingOrder(int, int);
-  }
-
-  public static class RecyclerView.EdgeEffectFactory {
-    ctor public RecyclerView.EdgeEffectFactory();
-    method protected android.widget.EdgeEffect createEdgeEffect(androidx.recyclerview.widget.RecyclerView, int);
-    field public static final int DIRECTION_BOTTOM = 3; // 0x3
-    field public static final int DIRECTION_LEFT = 0; // 0x0
-    field public static final int DIRECTION_RIGHT = 2; // 0x2
-    field public static final int DIRECTION_TOP = 1; // 0x1
-  }
-
-  public static abstract class RecyclerView.EdgeEffectFactory.EdgeDirection implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract class RecyclerView.ItemAnimator {
-    ctor public RecyclerView.ItemAnimator();
-    method public abstract boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object>);
-    method public final void dispatchAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAnimationsFinished();
-    method public abstract void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public abstract void endAnimations();
-    method public long getAddDuration();
-    method public long getChangeDuration();
-    method public long getMoveDuration();
-    method public long getRemoveDuration();
-    method public abstract boolean isRunning();
-    method public final boolean isRunning(androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener);
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
-    method public void onAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, java.util.List<java.lang.Object>);
-    method public abstract void runPendingAnimations();
-    method public void setAddDuration(long);
-    method public void setChangeDuration(long);
-    method public void setMoveDuration(long);
-    method public void setRemoveDuration(long);
-    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
-    field public static final int FLAG_CHANGED = 2; // 0x2
-    field public static final int FLAG_INVALIDATED = 4; // 0x4
-    field public static final int FLAG_MOVED = 2048; // 0x800
-    field public static final int FLAG_REMOVED = 8; // 0x8
-  }
-
-  public static abstract class RecyclerView.ItemAnimator.AdapterChanges implements java.lang.annotation.Annotation {
-  }
-
-  public static abstract interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
-    method public abstract void onAnimationsFinished();
-  }
-
-  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
-    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
-    field public int bottom;
-    field public int changeFlags;
-    field public int left;
-    field public int right;
-    field public int top;
-  }
-
-  public static abstract class RecyclerView.ItemDecoration {
-    ctor public RecyclerView.ItemDecoration();
-    method public deprecated void getItemOffsets(android.graphics.Rect, int, androidx.recyclerview.widget.RecyclerView);
-    method public void getItemOffsets(android.graphics.Rect, android.view.View, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
-    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
-    method public deprecated void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
-    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
-    method public deprecated void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
-  }
-
-  public static abstract class RecyclerView.LayoutManager {
-    ctor public RecyclerView.LayoutManager();
-    method public void addDisappearingView(android.view.View);
-    method public void addDisappearingView(android.view.View, int);
-    method public void addView(android.view.View);
-    method public void addView(android.view.View, int);
-    method public void assertInLayoutOrScroll(java.lang.String);
-    method public void assertNotInLayoutOrScroll(java.lang.String);
-    method public void attachView(android.view.View, int, androidx.recyclerview.widget.RecyclerView.LayoutParams);
-    method public void attachView(android.view.View, int);
-    method public void attachView(android.view.View);
-    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
-    method public boolean canScrollHorizontally();
-    method public boolean canScrollVertically();
-    method public boolean checkLayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams);
-    method public static int chooseSize(int, int, int);
-    method public void collectAdjacentPrefetchPositions(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
-    method public void collectInitialPrefetchPositions(int, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
-    method public int computeHorizontalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
-    method public int computeHorizontalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
-    method public int computeHorizontalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
-    method public int computeVerticalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
-    method public int computeVerticalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
-    method public int computeVerticalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
-    method public void detachAndScrapAttachedViews(androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public void detachAndScrapView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public void detachAndScrapViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public void detachView(android.view.View);
-    method public void detachViewAt(int);
-    method public void endAnimation(android.view.View);
-    method public android.view.View findContainingItemView(android.view.View);
-    method public android.view.View findViewByPosition(int);
-    method public abstract androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
-    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateLayoutParams(android.content.Context, android.util.AttributeSet);
-    method public int getBaseline();
-    method public int getBottomDecorationHeight(android.view.View);
-    method public android.view.View getChildAt(int);
-    method public int getChildCount();
-    method public static deprecated int getChildMeasureSpec(int, int, int, boolean);
-    method public static int getChildMeasureSpec(int, int, int, int, boolean);
-    method public boolean getClipToPadding();
-    method public int getColumnCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public int getDecoratedBottom(android.view.View);
-    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
-    method public int getDecoratedLeft(android.view.View);
-    method public int getDecoratedMeasuredHeight(android.view.View);
-    method public int getDecoratedMeasuredWidth(android.view.View);
-    method public int getDecoratedRight(android.view.View);
-    method public int getDecoratedTop(android.view.View);
-    method public android.view.View getFocusedChild();
-    method public int getHeight();
-    method public int getHeightMode();
-    method public int getItemCount();
-    method public int getItemViewType(android.view.View);
-    method public int getLayoutDirection();
-    method public int getLeftDecorationWidth(android.view.View);
-    method public int getMinimumHeight();
-    method public int getMinimumWidth();
-    method public int getPaddingBottom();
-    method public int getPaddingEnd();
-    method public int getPaddingLeft();
-    method public int getPaddingRight();
-    method public int getPaddingStart();
-    method public int getPaddingTop();
-    method public int getPosition(android.view.View);
-    method public static androidx.recyclerview.widget.RecyclerView.LayoutManager.Properties getProperties(android.content.Context, android.util.AttributeSet, int, int);
-    method public int getRightDecorationWidth(android.view.View);
-    method public int getRowCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public int getSelectionModeForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public int getTopDecorationHeight(android.view.View);
-    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
-    method public int getWidth();
-    method public int getWidthMode();
-    method public boolean hasFocus();
-    method public void ignoreView(android.view.View);
-    method public boolean isAttachedToWindow();
-    method public boolean isAutoMeasureEnabled();
-    method public boolean isFocused();
-    method public final boolean isItemPrefetchEnabled();
-    method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public boolean isMeasurementCacheEnabled();
-    method public boolean isSmoothScrolling();
-    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
-    method public void layoutDecorated(android.view.View, int, int, int, int);
-    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
-    method public void measureChild(android.view.View, int, int);
-    method public void measureChildWithMargins(android.view.View, int, int);
-    method public void moveView(int, int);
-    method public void offsetChildrenHorizontal(int);
-    method public void offsetChildrenVertical(int);
-    method public void onAdapterChanged(androidx.recyclerview.widget.RecyclerView.Adapter, androidx.recyclerview.widget.RecyclerView.Adapter);
-    method public boolean onAddFocusables(androidx.recyclerview.widget.RecyclerView, java.util.ArrayList<android.view.View>, int, int);
-    method public void onAttachedToWindow(androidx.recyclerview.widget.RecyclerView);
-    method public deprecated void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView);
-    method public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public android.view.View onFocusSearchFailed(android.view.View, int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onInitializeAccessibilityEvent(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
-    method public void onInitializeAccessibilityNodeInfo(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
-    method public void onInitializeAccessibilityNodeInfoForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
-    method public android.view.View onInterceptFocusSearch(android.view.View, int);
-    method public void onItemsAdded(androidx.recyclerview.widget.RecyclerView, int, int);
-    method public void onItemsChanged(androidx.recyclerview.widget.RecyclerView);
-    method public void onItemsMoved(androidx.recyclerview.widget.RecyclerView, int, int, int);
-    method public void onItemsRemoved(androidx.recyclerview.widget.RecyclerView, int, int);
-    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int);
-    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int, java.lang.Object);
-    method public void onLayoutChildren(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public void onLayoutCompleted(androidx.recyclerview.widget.RecyclerView.State);
-    method public void onMeasure(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, int);
-    method public deprecated boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, android.view.View, android.view.View);
-    method public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, android.view.View, android.view.View);
-    method public void onRestoreInstanceState(android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void onScrollStateChanged(int);
-    method public boolean performAccessibilityAction(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, android.os.Bundle);
-    method public boolean performAccessibilityActionForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, int, android.os.Bundle);
-    method public void postOnAnimation(java.lang.Runnable);
-    method public void removeAllViews();
-    method public void removeAndRecycleAllViews(androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public void removeAndRecycleView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public void removeAndRecycleViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
-    method public boolean removeCallbacks(java.lang.Runnable);
-    method public void removeDetachedView(android.view.View);
-    method public void removeView(android.view.View);
-    method public void removeViewAt(int);
-    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
-    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
-    method public void requestLayout();
-    method public void requestSimpleAnimationsInNextLayout();
-    method public int scrollHorizontallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public void scrollToPosition(int);
-    method public int scrollVerticallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
-    method public deprecated void setAutoMeasureEnabled(boolean);
-    method public final void setItemPrefetchEnabled(boolean);
-    method public void setMeasuredDimension(android.graphics.Rect, int, int);
-    method public void setMeasuredDimension(int, int);
-    method public void setMeasurementCacheEnabled(boolean);
-    method public void smoothScrollToPosition(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, int);
-    method public void startSmoothScroll(androidx.recyclerview.widget.RecyclerView.SmoothScroller);
-    method public void stopIgnoringView(android.view.View);
-    method public boolean supportsPredictiveItemAnimations();
-  }
-
-  public static abstract interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
-    method public abstract void addPosition(int, int);
-  }
-
-  public static class RecyclerView.LayoutManager.Properties {
-    ctor public RecyclerView.LayoutManager.Properties();
-    field public int orientation;
-    field public boolean reverseLayout;
-    field public int spanCount;
-    field public boolean stackFromEnd;
-  }
-
-  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public RecyclerView.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public RecyclerView.LayoutParams(int, int);
-    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public RecyclerView.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams);
-    method public int getViewAdapterPosition();
-    method public int getViewLayoutPosition();
-    method public deprecated int getViewPosition();
-    method public boolean isItemChanged();
-    method public boolean isItemRemoved();
-    method public boolean isViewInvalid();
-    method public boolean viewNeedsUpdate();
-  }
-
-  public static abstract interface RecyclerView.OnChildAttachStateChangeListener {
-    method public abstract void onChildViewAttachedToWindow(android.view.View);
-    method public abstract void onChildViewDetachedFromWindow(android.view.View);
-  }
-
-  public static abstract class RecyclerView.OnFlingListener {
-    ctor public RecyclerView.OnFlingListener();
-    method public abstract boolean onFling(int, int);
-  }
-
-  public static abstract interface RecyclerView.OnItemTouchListener {
-    method public abstract boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
-    method public abstract void onRequestDisallowInterceptTouchEvent(boolean);
-    method public abstract void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
-  }
-
-  public static abstract class RecyclerView.OnScrollListener {
-    ctor public RecyclerView.OnScrollListener();
-    method public void onScrollStateChanged(androidx.recyclerview.widget.RecyclerView, int);
-    method public void onScrolled(androidx.recyclerview.widget.RecyclerView, int, int);
-  }
-
-  public static class RecyclerView.RecycledViewPool {
-    ctor public RecyclerView.RecycledViewPool();
-    method public void clear();
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder getRecycledView(int);
-    method public int getRecycledViewCount(int);
-    method public void putRecycledView(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void setMaxRecycledViews(int, int);
-  }
-
-  public final class RecyclerView.Recycler {
-    ctor public RecyclerView.Recycler();
-    method public void bindViewToPosition(android.view.View, int);
-    method public void clear();
-    method public int convertPreLayoutPositionToPostLayout(int);
-    method public java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder> getScrapList();
-    method public android.view.View getViewForPosition(int);
-    method public void recycleView(android.view.View);
-    method public void setViewCacheSize(int);
-  }
-
-  public static abstract interface RecyclerView.RecyclerListener {
-    method public abstract void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-  }
-
-  public static class RecyclerView.SimpleOnItemTouchListener implements androidx.recyclerview.widget.RecyclerView.OnItemTouchListener {
-    ctor public RecyclerView.SimpleOnItemTouchListener();
-    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
-    method public void onRequestDisallowInterceptTouchEvent(boolean);
-    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
-  }
-
-  public static abstract class RecyclerView.SmoothScroller {
-    ctor public RecyclerView.SmoothScroller();
-    method public android.view.View findViewByPosition(int);
-    method public int getChildCount();
-    method public int getChildPosition(android.view.View);
-    method public androidx.recyclerview.widget.RecyclerView.LayoutManager getLayoutManager();
-    method public int getTargetPosition();
-    method public deprecated void instantScrollToPosition(int);
-    method public boolean isPendingInitialRun();
-    method public boolean isRunning();
-    method protected void normalize(android.graphics.PointF);
-    method protected void onChildAttachedToWindow(android.view.View);
-    method protected abstract void onSeekTargetStep(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
-    method protected abstract void onStart();
-    method protected abstract void onStop();
-    method protected abstract void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
-    method public void setTargetPosition(int);
-    method protected final void stop();
-  }
-
-  public static class RecyclerView.SmoothScroller.Action {
-    ctor public RecyclerView.SmoothScroller.Action(int, int);
-    ctor public RecyclerView.SmoothScroller.Action(int, int, int);
-    ctor public RecyclerView.SmoothScroller.Action(int, int, int, android.view.animation.Interpolator);
-    method public int getDuration();
-    method public int getDx();
-    method public int getDy();
-    method public android.view.animation.Interpolator getInterpolator();
-    method public void jumpTo(int);
-    method public void setDuration(int);
-    method public void setDx(int);
-    method public void setDy(int);
-    method public void setInterpolator(android.view.animation.Interpolator);
-    method public void update(int, int, int, android.view.animation.Interpolator);
-    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
-  }
-
-  public static abstract interface RecyclerView.SmoothScroller.ScrollVectorProvider {
-    method public abstract android.graphics.PointF computeScrollVectorForPosition(int);
-  }
-
-  public static class RecyclerView.State {
-    ctor public RecyclerView.State();
-    method public boolean didStructureChange();
-    method public <T> T get(int);
-    method public int getItemCount();
-    method public int getRemainingScrollHorizontal();
-    method public int getRemainingScrollVertical();
-    method public int getTargetScrollPosition();
-    method public boolean hasTargetScrollPosition();
-    method public boolean isMeasuring();
-    method public boolean isPreLayout();
-    method public void put(int, java.lang.Object);
-    method public void remove(int);
-    method public boolean willRunPredictiveAnimations();
-    method public boolean willRunSimpleAnimations();
-  }
-
-  public static abstract class RecyclerView.ViewCacheExtension {
-    ctor public RecyclerView.ViewCacheExtension();
-    method public abstract android.view.View getViewForPositionAndType(androidx.recyclerview.widget.RecyclerView.Recycler, int, int);
-  }
-
-  public static abstract class RecyclerView.ViewHolder {
-    ctor public RecyclerView.ViewHolder(android.view.View);
-    method public final int getAdapterPosition();
-    method public final long getItemId();
-    method public final int getItemViewType();
-    method public final int getLayoutPosition();
-    method public final int getOldPosition();
-    method public final deprecated int getPosition();
-    method public final boolean isRecyclable();
-    method public final void setIsRecyclable(boolean);
-    field public final android.view.View itemView;
-  }
-
-  public class RecyclerViewAccessibilityDelegate extends androidx.core.view.AccessibilityDelegateCompat {
-    ctor public RecyclerViewAccessibilityDelegate(androidx.recyclerview.widget.RecyclerView);
-    method public androidx.core.view.AccessibilityDelegateCompat getItemDelegate();
-  }
-
-  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends androidx.core.view.AccessibilityDelegateCompat {
-    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate);
-  }
-
-  public abstract class SimpleItemAnimator extends androidx.recyclerview.widget.RecyclerView.ItemAnimator {
-    ctor public SimpleItemAnimator();
-    method public abstract boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
-    method public boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
-    method public abstract boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder, boolean);
-    method public final void dispatchChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder, boolean);
-    method public final void dispatchMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public final void dispatchRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public boolean getSupportsChangeAnimations();
-    method public void onAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder, boolean);
-    method public void onChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder, boolean);
-    method public void onMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void setSupportsChangeAnimations(boolean);
-  }
-
-  public abstract class SnapHelper extends androidx.recyclerview.widget.RecyclerView.OnFlingListener {
-    ctor public SnapHelper();
-    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView) throws java.lang.IllegalStateException;
-    method public abstract int[] calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
-    method public int[] calculateScrollDistance(int, int);
-    method protected androidx.recyclerview.widget.RecyclerView.SmoothScroller createScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method protected deprecated androidx.recyclerview.widget.LinearSmoothScroller createSnapScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public abstract android.view.View findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
-    method public abstract int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
-    method public boolean onFling(int, int);
-  }
-
-  public class StaggeredGridLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
-    ctor public StaggeredGridLayoutManager(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public StaggeredGridLayoutManager(int, int);
-    method public android.graphics.PointF computeScrollVectorForPosition(int);
-    method public int[] findFirstCompletelyVisibleItemPositions(int[]);
-    method public int[] findFirstVisibleItemPositions(int[]);
-    method public int[] findLastCompletelyVisibleItemPositions(int[]);
-    method public int[] findLastVisibleItemPositions(int[]);
-    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
-    method public int getGapStrategy();
-    method public int getOrientation();
-    method public boolean getReverseLayout();
-    method public int getSpanCount();
-    method public void invalidateSpanAssignments();
-    method public void scrollToPositionWithOffset(int, int);
-    method public void setGapStrategy(int);
-    method public void setOrientation(int);
-    method public void setReverseLayout(boolean);
-    method public void setSpanCount(int);
-    field public static final deprecated int GAP_HANDLING_LAZY = 1; // 0x1
-    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
-    field public static final int GAP_HANDLING_NONE = 0; // 0x0
-    field public static final int HORIZONTAL = 0; // 0x0
-    field public static final int VERTICAL = 1; // 0x1
-  }
-
-  public static class StaggeredGridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
-    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
-    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public StaggeredGridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams);
-    method public final int getSpanIndex();
-    method public boolean isFullSpan();
-    method public void setFullSpan(boolean);
-    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
-  }
-
-}
-
-package androidx.recyclerview.widget {
-
-  public class ItemTouchHelper extends androidx.recyclerview.widget.RecyclerView.ItemDecoration implements androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener {
-    ctor public ItemTouchHelper(androidx.recyclerview.widget.ItemTouchHelper.Callback);
-    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView);
-    method public void onChildViewAttachedToWindow(android.view.View);
-    method public void onChildViewDetachedFromWindow(android.view.View);
-    method public void startDrag(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void startSwipe(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    field public static final int ACTION_STATE_DRAG = 2; // 0x2
-    field public static final int ACTION_STATE_IDLE = 0; // 0x0
-    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
-    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
-    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
-    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
-    field public static final int DOWN = 2; // 0x2
-    field public static final int END = 32; // 0x20
-    field public static final int LEFT = 4; // 0x4
-    field public static final int RIGHT = 8; // 0x8
-    field public static final int START = 16; // 0x10
-    field public static final int UP = 1; // 0x1
-  }
-
-  public static abstract class ItemTouchHelper.Callback {
-    ctor public ItemTouchHelper.Callback();
-    method public boolean canDropOver(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public androidx.recyclerview.widget.RecyclerView.ViewHolder chooseDropTarget(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder>, int, int);
-    method public void clearView(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public int convertToAbsoluteDirection(int, int);
-    method public static int convertToRelativeDirection(int, int);
-    method public long getAnimationDuration(androidx.recyclerview.widget.RecyclerView, int, float, float);
-    method public int getBoundingBoxMargin();
-    method public static androidx.recyclerview.widget.ItemTouchUIUtil getDefaultUIUtil();
-    method public float getMoveThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public abstract int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public float getSwipeEscapeVelocity(float);
-    method public float getSwipeThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public float getSwipeVelocityThreshold(float);
-    method public int interpolateOutOfBoundsScroll(androidx.recyclerview.widget.RecyclerView, int, int, int, long);
-    method public boolean isItemViewSwipeEnabled();
-    method public boolean isLongPressDragEnabled();
-    method public static int makeFlag(int, int);
-    method public static int makeMovementFlags(int, int);
-    method public void onChildDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
-    method public void onChildDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
-    method public abstract boolean onMove(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void onMoved(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int);
-    method public void onSelectedChanged(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
-    method public abstract void onSwiped(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
-    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
-    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
-  }
-
-  public static abstract class ItemTouchHelper.SimpleCallback extends androidx.recyclerview.widget.ItemTouchHelper.Callback {
-    ctor public ItemTouchHelper.SimpleCallback(int, int);
-    method public int getDragDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public int getSwipeDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
-    method public void setDefaultDragDirs(int);
-    method public void setDefaultSwipeDirs(int);
-  }
-
-  public static abstract interface ItemTouchHelper.ViewDropHandler {
-    method public abstract void prepareForDrop(android.view.View, android.view.View, int, int);
-  }
-
-  public abstract interface ItemTouchUIUtil {
-    method public abstract void clearView(android.view.View);
-    method public abstract void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
-    method public abstract void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
-    method public abstract void onSelected(android.view.View);
-  }
-
-  public abstract class SortedListAdapterCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback {
-    ctor public SortedListAdapterCallback(androidx.recyclerview.widget.RecyclerView.Adapter);
-    method public void onChanged(int, int);
-    method public void onInserted(int, int);
-    method public void onMoved(int, int);
-    method public void onRemoved(int, int);
-  }
-
-}
-
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
index b47ae73..1e9c22f 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlPlugin.kt
@@ -48,12 +48,10 @@
             StableAidlExtensionImpl::class.java
         )
 
-        // Obtain the AIDL executable and framework AIDL file paths using private APIs. See
-        // b/268237729 for public API request, after which we can obtain them from SdkComponents.
-        val base = project.extensions.getByType(BaseExtension::class.java)
-            ?: throw GradleException("Stable AIDL plugin requires Android Gradle Plugin")
-        val aidlExecutable = androidComponents.sdkComponents.aidl(base)
-        val aidlFramework = androidComponents.sdkComponents.aidlFramework(base)
+        val aidl = androidComponents.sdkComponents.aidl.get()
+        val aidlExecutable = aidl.executable
+        val aidlFramework = aidl.framework
+        val aidlVersion = aidl.version
 
         // Extend the android sourceSet.
         androidComponents.registerSourceType(SOURCE_TYPE_STABLE_AIDL)
@@ -99,6 +97,7 @@
                 variant,
                 aidlExecutable,
                 aidlFramework,
+                aidlVersion,
                 sourceDir,
                 packagedDir,
                 importsDir,
@@ -119,6 +118,7 @@
                 variant,
                 aidlExecutable,
                 aidlFramework,
+                aidlVersion,
                 sourceDir,
                 importsDir,
                 depImports,
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
index 4b88d94..a8c0775 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/StableAidlTasks.kt
@@ -74,6 +74,7 @@
     variant: Variant,
     aidlExecutable: Provider<RegularFile>,
     aidlFramework: Provider<RegularFile>,
+    aidlVersion: Provider<String>,
     sourceDir: SourceDirectories.Flat,
     packagedDir: Provider<Directory>,
     importsDir: SourceDirectories.Flat,
@@ -88,6 +89,8 @@
     task.variantName = variant.name
     task.aidlExecutable.set(aidlExecutable)
     task.aidlFrameworkProvider.set(aidlFramework)
+    task.aidlVersion.set(aidlVersion)
+    task.minSdkVersion.set(variant.minSdk)
     task.sourceDirs.set(sourceDir.all)
     task.sourceOutputDir.set(outputDir)
     task.packagedDir.set(packagedDir)
@@ -160,6 +163,7 @@
     variant: Variant,
     aidlExecutable: Provider<RegularFile>,
     aidlFramework: Provider<RegularFile>,
+    aidlVersion: Provider<String>,
     sourceDir: SourceDirectories.Flat,
     importsDir: SourceDirectories.Flat,
     depImports: List<FileCollection>,
@@ -174,6 +178,7 @@
     task.variantName = variant.name
     task.aidlExecutable.set(aidlExecutable)
     task.aidlFrameworkProvider.set(aidlFramework)
+    task.aidlVersion.set(aidlVersion)
     task.sourceDirs.set(sourceDir.all)
     task.sourceOutputDir.set(builtApiDir)
     task.importDirs.set(importsDir.all)
diff --git a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/tasks/StableAidlCompile.kt b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/tasks/StableAidlCompile.kt
index da583c2..53f4b61 100644
--- a/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/tasks/StableAidlCompile.kt
+++ b/stableaidl/stableaidl-gradle-plugin/src/main/java/androidx/stableaidl/tasks/StableAidlCompile.kt
@@ -21,6 +21,7 @@
 import androidx.stableaidl.internal.compiling.DependencyFileProcessor
 import androidx.stableaidl.internal.incremental.DependencyData
 import androidx.stableaidl.internal.process.GradleProcessExecutor
+import com.android.build.api.variant.AndroidVersion
 import com.android.ide.common.process.LoggedProcessOutputHandler
 import com.android.utils.FileUtils
 import com.google.common.annotations.VisibleForTesting
@@ -91,6 +92,19 @@
     @get:PathSensitive(PathSensitivity.NONE)
     abstract val aidlExecutable: RegularFileProperty
 
+    @get:Input
+    abstract val aidlVersion: Property<String>
+
+    /**
+     * Variant's minimum SDK version.
+     *
+     * This should only be specified when generating code. Do not specify this when dumping the API
+     * surface, e.g. passing `--dumpapi` as an extra argument.
+     */
+    @get:Input
+    @get:Optional
+    abstract val minSdkVersion: Property<AndroidVersion>
+
     /**
      * Directory for storing AIDL-generated Java sources.
      */
@@ -135,13 +149,22 @@
         val fullImportList = sourceDirs.get() + importDirs.get()
         val sourceDirsAsFiles = sourceDirs.get().map { it.asFile }
 
+        // When using AIDL from build tools version 33 and later, pass the variant's minimum SDK
+        // version. If it's a pre-release SDK, pass the most recently stabilized SDK version.
+        val aidlMajorVersion = aidlVersion.get().substringBefore('.').toIntOrNull() ?: 0
+        val extraArgsWithSdk = if (minSdkVersion.isPresent && aidlMajorVersion >= 33) {
+            extraArgs.get() + listOf("--min_sdk_version", "${minSdkVersion.get().apiLevel}")
+        } else {
+            extraArgs.get()
+        }
+
         aidlCompileDelegate(
             workerExecutor,
             aidlExecutable.get().asFile,
             aidlFrameworkProvider.get().asFile,
             destinationDir,
             parcelableDir?.asFile,
-            extraArgs.get(),
+            extraArgsWithSdk,
             sourceDirsAsFiles,
             fullImportList,
             dependencyImportDirs.get().map { it.asFile }
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
index 368a225..0e0c05b 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt
@@ -86,8 +86,8 @@
         ellipsize: TruncateAt? = null,
         ellipsizedWidth: Int = width,
     ): BoringLayout {
-        require(width >= 0)
-        require(ellipsizedWidth >= 0)
+        require(width >= 0) { "negative width" }
+        require(ellipsizedWidth >= 0) { "negative ellipsized width" }
 
         return if (Build.VERSION.SDK_INT >= 33) {
             BoringLayoutFactory33.create(
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt b/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
index 88ef45f..62ccdd9 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt
@@ -153,12 +153,12 @@
     val rightIndents: IntArray?
 ) {
     init {
-        require(start in 0..end)
-        require(end in 0..text.length)
-        require(maxLines >= 0)
-        require(width >= 0)
-        require(ellipsizedWidth >= 0)
-        require(lineSpacingMultiplier >= 0f)
+        require(start in 0..end) { "invalid start value" }
+        require(end in 0..text.length) { "invalid end value" }
+        require(maxLines >= 0) { "invalid maxLines value" }
+        require(width >= 0) { "invalid width value" }
+        require(ellipsizedWidth >= 0) { "invalid ellipsizedWidth value" }
+        require(lineSpacingMultiplier >= 0f) { "invalid lineSpacingMultiplier value" }
     }
 }
 
diff --git a/transition/transition/api/0.0.0.txt b/transition/transition/api/0.0.0.txt
deleted file mode 100644
index 1ce2f43..0000000
--- a/transition/transition/api/0.0.0.txt
+++ /dev/null
@@ -1,280 +0,0 @@
-package androidx.transition {
-
-  public class ArcMotion extends androidx.transition.PathMotion {
-    ctor public ArcMotion();
-    ctor public ArcMotion(android.content.Context, android.util.AttributeSet);
-    method public float getMaximumAngle();
-    method public float getMinimumHorizontalAngle();
-    method public float getMinimumVerticalAngle();
-    method public android.graphics.Path getPath(float, float, float, float);
-    method public void setMaximumAngle(float);
-    method public void setMinimumHorizontalAngle(float);
-    method public void setMinimumVerticalAngle(float);
-  }
-
-  public class AutoTransition extends androidx.transition.TransitionSet {
-    ctor public AutoTransition();
-    ctor public AutoTransition(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class ChangeBounds extends androidx.transition.Transition {
-    ctor public ChangeBounds();
-    ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-    method public boolean getResizeClip();
-    method public void setResizeClip(boolean);
-  }
-
-  public class ChangeClipBounds extends androidx.transition.Transition {
-    ctor public ChangeClipBounds();
-    ctor public ChangeClipBounds(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-  }
-
-  public class ChangeImageTransform extends androidx.transition.Transition {
-    ctor public ChangeImageTransform();
-    ctor public ChangeImageTransform(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-  }
-
-  public class ChangeScroll extends androidx.transition.Transition {
-    ctor public ChangeScroll();
-    ctor public ChangeScroll(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-  }
-
-  public class ChangeTransform extends androidx.transition.Transition {
-    ctor public ChangeTransform();
-    ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-    method public boolean getReparent();
-    method public boolean getReparentWithOverlay();
-    method public void setReparent(boolean);
-    method public void setReparentWithOverlay(boolean);
-  }
-
-  public class CircularPropagation extends androidx.transition.VisibilityPropagation {
-    ctor public CircularPropagation();
-    method public long getStartDelay(android.view.ViewGroup, androidx.transition.Transition, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public void setPropagationSpeed(float);
-  }
-
-  public class Explode extends androidx.transition.Visibility {
-    ctor public Explode();
-    ctor public Explode(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class Fade extends androidx.transition.Visibility {
-    ctor public Fade(int);
-    ctor public Fade();
-    ctor public Fade(android.content.Context, android.util.AttributeSet);
-    field public static final int IN = 1; // 0x1
-    field public static final int OUT = 2; // 0x2
-  }
-
-  public abstract class PathMotion {
-    ctor public PathMotion();
-    ctor public PathMotion(android.content.Context, android.util.AttributeSet);
-    method public abstract android.graphics.Path getPath(float, float, float, float);
-  }
-
-  public class PatternPathMotion extends androidx.transition.PathMotion {
-    ctor public PatternPathMotion();
-    ctor public PatternPathMotion(android.content.Context, android.util.AttributeSet);
-    ctor public PatternPathMotion(android.graphics.Path);
-    method public android.graphics.Path getPath(float, float, float, float);
-    method public android.graphics.Path getPatternPath();
-    method public void setPatternPath(android.graphics.Path);
-  }
-
-  public class Scene {
-    ctor public Scene(android.view.ViewGroup);
-    ctor public Scene(android.view.ViewGroup, android.view.View);
-    method public void enter();
-    method public void exit();
-    method public static androidx.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
-    method public android.view.ViewGroup getSceneRoot();
-    method public void setEnterAction(java.lang.Runnable);
-    method public void setExitAction(java.lang.Runnable);
-  }
-
-  public class SidePropagation extends androidx.transition.VisibilityPropagation {
-    ctor public SidePropagation();
-    method public long getStartDelay(android.view.ViewGroup, androidx.transition.Transition, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public void setPropagationSpeed(float);
-    method public void setSide(int);
-  }
-
-  public class Slide extends androidx.transition.Visibility {
-    ctor public Slide();
-    ctor public Slide(int);
-    ctor public Slide(android.content.Context, android.util.AttributeSet);
-    method public int getSlideEdge();
-    method public void setSlideEdge(int);
-  }
-
-  public abstract class Transition implements java.lang.Cloneable {
-    ctor public Transition();
-    ctor public Transition(android.content.Context, android.util.AttributeSet);
-    method public androidx.transition.Transition addListener(androidx.transition.Transition.TransitionListener);
-    method public androidx.transition.Transition addTarget(android.view.View);
-    method public androidx.transition.Transition addTarget(int);
-    method public androidx.transition.Transition addTarget(java.lang.String);
-    method public androidx.transition.Transition addTarget(java.lang.Class);
-    method public abstract void captureEndValues(androidx.transition.TransitionValues);
-    method public abstract void captureStartValues(androidx.transition.TransitionValues);
-    method public androidx.transition.Transition clone();
-    method public android.animation.Animator createAnimator(android.view.ViewGroup, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public androidx.transition.Transition excludeChildren(android.view.View, boolean);
-    method public androidx.transition.Transition excludeChildren(int, boolean);
-    method public androidx.transition.Transition excludeChildren(java.lang.Class, boolean);
-    method public androidx.transition.Transition excludeTarget(android.view.View, boolean);
-    method public androidx.transition.Transition excludeTarget(int, boolean);
-    method public androidx.transition.Transition excludeTarget(java.lang.String, boolean);
-    method public androidx.transition.Transition excludeTarget(java.lang.Class, boolean);
-    method public long getDuration();
-    method public android.graphics.Rect getEpicenter();
-    method public androidx.transition.Transition.EpicenterCallback getEpicenterCallback();
-    method public android.animation.TimeInterpolator getInterpolator();
-    method public java.lang.String getName();
-    method public androidx.transition.PathMotion getPathMotion();
-    method public androidx.transition.TransitionPropagation getPropagation();
-    method public long getStartDelay();
-    method public java.util.List<java.lang.Integer> getTargetIds();
-    method public java.util.List<java.lang.String> getTargetNames();
-    method public java.util.List<java.lang.Class> getTargetTypes();
-    method public java.util.List<android.view.View> getTargets();
-    method public java.lang.String[] getTransitionProperties();
-    method public androidx.transition.TransitionValues getTransitionValues(android.view.View, boolean);
-    method public boolean isTransitionRequired(androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public androidx.transition.Transition removeListener(androidx.transition.Transition.TransitionListener);
-    method public androidx.transition.Transition removeTarget(android.view.View);
-    method public androidx.transition.Transition removeTarget(int);
-    method public androidx.transition.Transition removeTarget(java.lang.String);
-    method public androidx.transition.Transition removeTarget(java.lang.Class);
-    method public androidx.transition.Transition setDuration(long);
-    method public void setEpicenterCallback(androidx.transition.Transition.EpicenterCallback);
-    method public androidx.transition.Transition setInterpolator(android.animation.TimeInterpolator);
-    method public void setMatchOrder(int...);
-    method public void setPathMotion(androidx.transition.PathMotion);
-    method public void setPropagation(androidx.transition.TransitionPropagation);
-    method public androidx.transition.Transition setStartDelay(long);
-    field public static final int MATCH_ID = 3; // 0x3
-    field public static final int MATCH_INSTANCE = 1; // 0x1
-    field public static final int MATCH_ITEM_ID = 4; // 0x4
-    field public static final int MATCH_NAME = 2; // 0x2
-  }
-
-  public static abstract class Transition.EpicenterCallback {
-    ctor public Transition.EpicenterCallback();
-    method public abstract android.graphics.Rect onGetEpicenter(androidx.transition.Transition);
-  }
-
-  public static abstract interface Transition.TransitionListener {
-    method public abstract void onTransitionCancel(androidx.transition.Transition);
-    method public abstract void onTransitionEnd(androidx.transition.Transition);
-    method public abstract void onTransitionPause(androidx.transition.Transition);
-    method public abstract void onTransitionResume(androidx.transition.Transition);
-    method public abstract void onTransitionStart(androidx.transition.Transition);
-  }
-
-  public class TransitionInflater {
-    method public static androidx.transition.TransitionInflater from(android.content.Context);
-    method public androidx.transition.Transition inflateTransition(int);
-    method public androidx.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
-  }
-
-  public class TransitionListenerAdapter implements androidx.transition.Transition.TransitionListener {
-    ctor public TransitionListenerAdapter();
-    method public void onTransitionCancel(androidx.transition.Transition);
-    method public void onTransitionEnd(androidx.transition.Transition);
-    method public void onTransitionPause(androidx.transition.Transition);
-    method public void onTransitionResume(androidx.transition.Transition);
-    method public void onTransitionStart(androidx.transition.Transition);
-  }
-
-  public class TransitionManager {
-    ctor public TransitionManager();
-    method public static void beginDelayedTransition(android.view.ViewGroup);
-    method public static void beginDelayedTransition(android.view.ViewGroup, androidx.transition.Transition);
-    method public static void endTransitions(android.view.ViewGroup);
-    method public static void go(androidx.transition.Scene);
-    method public static void go(androidx.transition.Scene, androidx.transition.Transition);
-    method public void setTransition(androidx.transition.Scene, androidx.transition.Transition);
-    method public void setTransition(androidx.transition.Scene, androidx.transition.Scene, androidx.transition.Transition);
-    method public void transitionTo(androidx.transition.Scene);
-  }
-
-  public abstract class TransitionPropagation {
-    ctor public TransitionPropagation();
-    method public abstract void captureValues(androidx.transition.TransitionValues);
-    method public abstract java.lang.String[] getPropagationProperties();
-    method public abstract long getStartDelay(android.view.ViewGroup, androidx.transition.Transition, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-  }
-
-  public class TransitionSet extends androidx.transition.Transition {
-    ctor public TransitionSet();
-    ctor public TransitionSet(android.content.Context, android.util.AttributeSet);
-    method public androidx.transition.TransitionSet addListener(androidx.transition.Transition.TransitionListener);
-    method public androidx.transition.TransitionSet addTarget(android.view.View);
-    method public androidx.transition.TransitionSet addTarget(int);
-    method public androidx.transition.TransitionSet addTarget(java.lang.String);
-    method public androidx.transition.TransitionSet addTarget(java.lang.Class);
-    method public androidx.transition.TransitionSet addTransition(androidx.transition.Transition);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-    method public int getOrdering();
-    method public androidx.transition.Transition getTransitionAt(int);
-    method public int getTransitionCount();
-    method public androidx.transition.TransitionSet removeListener(androidx.transition.Transition.TransitionListener);
-    method public androidx.transition.TransitionSet removeTarget(int);
-    method public androidx.transition.TransitionSet removeTarget(android.view.View);
-    method public androidx.transition.TransitionSet removeTarget(java.lang.Class);
-    method public androidx.transition.TransitionSet removeTarget(java.lang.String);
-    method public androidx.transition.TransitionSet removeTransition(androidx.transition.Transition);
-    method public androidx.transition.TransitionSet setDuration(long);
-    method public androidx.transition.TransitionSet setInterpolator(android.animation.TimeInterpolator);
-    method public androidx.transition.TransitionSet setOrdering(int);
-    method public androidx.transition.TransitionSet setStartDelay(long);
-    field public static final int ORDERING_SEQUENTIAL = 1; // 0x1
-    field public static final int ORDERING_TOGETHER = 0; // 0x0
-  }
-
-  public class TransitionValues {
-    ctor public TransitionValues();
-    field public final java.util.Map<java.lang.String, java.lang.Object> values;
-    field public android.view.View view;
-  }
-
-  public abstract class Visibility extends androidx.transition.Transition {
-    ctor public Visibility();
-    ctor public Visibility(android.content.Context, android.util.AttributeSet);
-    method public void captureEndValues(androidx.transition.TransitionValues);
-    method public void captureStartValues(androidx.transition.TransitionValues);
-    method public int getMode();
-    method public boolean isVisible(androidx.transition.TransitionValues);
-    method public android.animation.Animator onAppear(android.view.ViewGroup, androidx.transition.TransitionValues, int, androidx.transition.TransitionValues, int);
-    method public android.animation.Animator onAppear(android.view.ViewGroup, android.view.View, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public android.animation.Animator onDisappear(android.view.ViewGroup, androidx.transition.TransitionValues, int, androidx.transition.TransitionValues, int);
-    method public android.animation.Animator onDisappear(android.view.ViewGroup, android.view.View, androidx.transition.TransitionValues, androidx.transition.TransitionValues);
-    method public void setMode(int);
-    field public static final int MODE_IN = 1; // 0x1
-    field public static final int MODE_OUT = 2; // 0x2
-  }
-
-  public abstract class VisibilityPropagation extends androidx.transition.TransitionPropagation {
-    ctor public VisibilityPropagation();
-    method public void captureValues(androidx.transition.TransitionValues);
-    method public java.lang.String[] getPropagationProperties();
-    method public int getViewVisibility(androidx.transition.TransitionValues);
-    method public int getViewX(androidx.transition.TransitionValues);
-    method public int getViewY(androidx.transition.TransitionValues);
-  }
-
-}
-
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
index 9d04904..b95b687 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
@@ -222,9 +222,13 @@
         state.slotsPerLine = resolvedSlotSizesSums.size
 
         val spaceBetweenLinesDp = if (isVertical) {
-            requireNotNull(verticalArrangement).spacing
+            requireNotNull(verticalArrangement) {
+                "encountered null verticalArrangement when isVertical == true"
+            }.spacing
         } else {
-            requireNotNull(horizontalArrangement).spacing
+            requireNotNull(horizontalArrangement) {
+                "encountered null horizontalArrangement when isVertical == false"
+            }.spacing
         }
         val spaceBetweenLines = spaceBetweenLinesDp.roundToPx()
         val spaceBetweenSlotsDp = if (isVertical) {
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridDsl.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridDsl.kt
index d1f3d6b..97b3af4 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridDsl.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridDsl.kt
@@ -228,7 +228,7 @@
      */
     class Fixed(private val count: Int) : TvGridCells {
         init {
-            require(count > 0)
+            require(count > 0) { "grid with no rows/columns" }
         }
 
         override fun Density.calculateCrossAxisCellSizes(
@@ -258,7 +258,7 @@
      */
     class Adaptive(private val minSize: Dp) : TvGridCells {
         init {
-            require(minSize > 0.dp)
+            require(minSize > 0.dp) { "Grid requires a positive minSize" }
         }
 
         override fun Density.calculateCrossAxisCellSizes(
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridMeasure.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridMeasure.kt
index f8c356c..837f940 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridMeasure.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridMeasure.kt
@@ -65,8 +65,8 @@
     @Suppress("PrimitiveInLambda")
     layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
 ): TvLazyGridMeasureResult {
-    require(beforeContentPadding >= 0)
-    require(afterContentPadding >= 0)
+    require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
+    require(afterContentPadding >= 0) { "negative afterContentPadding" }
     if (itemsCount <= 0) {
         // empty data set. reset the current scroll and report zero size
         return TvLazyGridMeasureResult(
@@ -205,7 +205,7 @@
         }
 
         // the initial offset for lines from visibleLines list
-        require(currentFirstLineScrollOffset >= 0)
+        require(currentFirstLineScrollOffset >= 0) { "invalid initial offset" }
         val visibleLinesScrollOffset = -currentFirstLineScrollOffset
         var firstLine = visibleLines.first()
 
@@ -356,13 +356,15 @@
     val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
     val hasSpareSpace = finalMainAxisOffset < min(mainAxisLayoutSize, maxOffset)
     if (hasSpareSpace) {
-        check(firstLineScrollOffset == 0)
+        check(firstLineScrollOffset == 0) { "invalid firstLineScrollOffset" }
     }
 
     val positionedItems = ArrayList<LazyGridPositionedItem>(lines.fastSumBy { it.items.size })
 
     if (hasSpareSpace) {
-        require(itemsBefore.isEmpty() && itemsAfter.isEmpty())
+        require(itemsBefore.isEmpty() && itemsAfter.isEmpty()) {
+            "existing out of bounds items"
+        }
         val linesCount = lines.size
         fun Int.reverseAware() =
             if (!reverseLayout) this else linesCount - this - 1
@@ -372,11 +374,19 @@
         }
         val offsets = IntArray(linesCount) { 0 }
         if (isVertical) {
-            with(requireNotNull(verticalArrangement)) {
+            with(
+                requireNotNull(verticalArrangement) {
+                    "null verticalArrangement when isVertical = true"
+                }
+            ) {
                 density.arrange(mainAxisLayoutSize, sizes, offsets)
             }
         } else {
-            with(requireNotNull(horizontalArrangement)) {
+            with(
+                requireNotNull(horizontalArrangement) {
+                    "null horizontalArrangement when isVertical = false"
+                }
+            ) {
                 // Enforces Ltr layout direction as it is mirrored with placeRelative later.
                 density.arrange(mainAxisLayoutSize, sizes, LayoutDirection.Ltr, offsets)
             }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
index 788722e..4840bcf 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGridSpanLayoutProvider.kt
@@ -111,7 +111,7 @@
             cachedBucket.clear()
         }
 
-        check(currentLine <= lineIndex)
+        check(currentLine <= lineIndex) { "invalid currentLine" }
 
         while (currentLine < lineIndex && currentItemIndex < totalSize) {
             if (cacheThisBucket) {
@@ -137,7 +137,7 @@
             if (currentLine % bucketSize == 0 && currentItemIndex < totalSize) {
                 val currentLineBucket = currentLine / bucketSize
                 // This should happen, as otherwise this should have been used as starting point.
-                check(buckets.size == currentLineBucket)
+                check(buckets.size == currentLineBucket) { "invalid starting point" }
                 buckets.add(Bucket(currentItemIndex, knownCurrentItemSpan))
             }
         }
@@ -172,7 +172,7 @@
         if (totalSize <= 0) {
             return LineIndex(0)
         }
-        require(itemIndex < totalSize)
+        require(itemIndex < totalSize) { "invalid itemIndex" }
         if (!gridContent.hasCustomSpans) {
             return LineIndex(itemIndex / slotsPerLine)
         }
@@ -183,7 +183,7 @@
         var currentLine = lowerBoundBucket * bucketSize
         var currentItemIndex = buckets[lowerBoundBucket].firstItemIndex
 
-        require(currentItemIndex <= itemIndex)
+        require(currentItemIndex <= itemIndex) { "invalid currentItemIndex" }
         var spansUsed = 0
         while (currentItemIndex < itemIndex) {
             val span = spanOf(currentItemIndex++, slotsPerLine - spansUsed)
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyMeasuredItemProvider.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyMeasuredItemProvider.kt
index 4e1cabc..1329963 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyMeasuredItemProvider.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyMeasuredItemProvider.kt
@@ -47,7 +47,7 @@
         val crossAxisSize = if (constraints.hasFixedWidth) {
             constraints.minWidth
         } else {
-            require(constraints.hasFixedHeight)
+            require(constraints.hasFixedHeight) { "constraints require fixed height" }
             constraints.minHeight
         }
         return measuredItemFactory.createItem(
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
index 0480d58..2300956 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/layout/LazyLayoutKeyIndexMap.kt
@@ -113,7 +113,7 @@
             list: IntervalList<LazyLayoutIntervalContent.Interval>
         ): Map<Any, Int> {
             val first = range.first
-            check(first >= 0)
+            check(first >= 0) { "Invalid start of range" }
             val last = minOf(range.last, list.size - 1)
             return if (last < first) {
                 emptyMap()
@@ -124,7 +124,7 @@
                         toIndex = last,
                     ) {
                         if (it.value.key != null) {
-                            @Suppress("PrimitiveInLambda")
+                            @Suppress("PrimitiveInLambda", "ExceptionMessage")
                             val keyFactory = requireNotNull(it.value.key)
                             val start = maxOf(first, it.startIndex)
                             val end = minOf(last, it.startIndex + it.size - 1)
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
index eb05a8e..224af43 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
@@ -237,9 +237,13 @@
         )
 
         val spaceBetweenItemsDp = if (isVertical) {
-            requireNotNull(verticalArrangement).spacing
+            requireNotNull(verticalArrangement) {
+                "encountered null verticalArrangement when isVertical == true"
+            }.spacing
         } else {
-            requireNotNull(horizontalArrangement).spacing
+            requireNotNull(horizontalArrangement) {
+                "encountered null horizontalArrangement when isVertical == false"
+            }.spacing
         }
         val spaceBetweenItems = spaceBetweenItemsDp.roundToPx()
 
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsInfo.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsInfo.kt
index f578b2c..e8044b3 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsInfo.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListBeyondBoundsInfo.kt
@@ -89,7 +89,7 @@
                     minIndex = it.start
                 }
             }
-            require(minIndex >= 0)
+            require(minIndex >= 0) { "negative minIndex" }
             return minIndex
         }
 
@@ -118,8 +118,8 @@
         val end: Int
     ) {
         init {
-            require(start >= 0)
-            require(end >= start)
+            require(start >= 0) { "negative start index" }
+            require(end >= start) { "end < start" }
         }
     }
 }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasure.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasure.kt
index baa04be..fec6f61 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasure.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasure.kt
@@ -66,8 +66,8 @@
     @Suppress("PrimitiveInLambda")
     layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
 ): LazyListMeasureResult {
-    require(beforeContentPadding >= 0)
-    require(afterContentPadding >= 0)
+    require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
+    require(afterContentPadding >= 0) { "negative afterContentPadding" }
     if (itemsCount <= 0) {
         // empty data set. reset the current scroll and report zero size
         return LazyListMeasureResult(
@@ -215,7 +215,7 @@
         }
 
         // the initial offset for items from visibleItems list
-        require(currentFirstItemScrollOffset >= 0)
+        require(currentFirstItemScrollOffset >= 0) { "negative scroll offset" }
         val visibleItemsScrollOffset = -currentFirstItemScrollOffset
         var firstItem = visibleItems.first()
 
@@ -361,7 +361,8 @@
 
     fun addItem(index: Int) {
         if (list == null) list = mutableListOf()
-        requireNotNull(list).add(
+        @Suppress("ExceptionMessage")
+        checkNotNull(list).add(
             measuredItemProvider.getAndMeasure(DataIndex(index))
         )
     }
@@ -405,9 +406,8 @@
 
     fun addItem(index: Int) {
         if (list == null) list = mutableListOf()
-        requireNotNull(list).add(
-            measuredItemProvider.getAndMeasure(DataIndex(index))
-        )
+        @Suppress("ExceptionMessage")
+        checkNotNull(list).add(measuredItemProvider.getAndMeasure(DataIndex(index)))
     }
 
     if (beyondBoundsInfo.hasIntervals()) {
@@ -451,14 +451,14 @@
     val mainAxisLayoutSize = if (isVertical) layoutHeight else layoutWidth
     val hasSpareSpace = finalMainAxisOffset < minOf(mainAxisLayoutSize, maxOffset)
     if (hasSpareSpace) {
-        check(itemsScrollOffset == 0)
+        check(itemsScrollOffset == 0) { "non-zero itemsScrollOffset" }
     }
 
     val positionedItems =
         ArrayList<LazyListPositionedItem>(items.size + extraItemsBefore.size + extraItemsAfter.size)
 
     if (hasSpareSpace) {
-        require(extraItemsBefore.isEmpty() && extraItemsAfter.isEmpty())
+        require(extraItemsBefore.isEmpty() && extraItemsAfter.isEmpty()) { "no extra items" }
 
         val itemsCount = items.size
         fun Int.reverseAware() =
@@ -469,11 +469,11 @@
         }
         val offsets = IntArray(itemsCount) { 0 }
         if (isVertical) {
-            with(requireNotNull(verticalArrangement)) {
+            with(requireNotNull(verticalArrangement) { "null verticalArrangement" }) {
                 density.arrange(mainAxisLayoutSize, sizes, offsets)
             }
         } else {
-            with(requireNotNull(horizontalArrangement)) {
+            with(requireNotNull(horizontalArrangement) { "null horizontalAlignment" }) {
                 // Enforces Ltr layout direction as it is mirrored with placeRelative later.
                 density.arrange(mainAxisLayoutSize, sizes, LayoutDirection.Ltr, offsets)
             }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyMeasuredItem.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyMeasuredItem.kt
index da7dcda..b1326406 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyMeasuredItem.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyMeasuredItem.kt
@@ -93,11 +93,12 @@
         var mainAxisOffset = offset
         placeables.fastForEach {
             val placeableOffset = if (isVertical) {
-                val x = requireNotNull(horizontalAlignment)
+                val x = requireNotNull(horizontalAlignment) { "null horizontalAlignment" }
                     .align(it.width, layoutWidth, layoutDirection)
                 IntOffset(x, mainAxisOffset)
             } else {
-                val y = requireNotNull(verticalAlignment).align(it.height, layoutHeight)
+                val y = requireNotNull(verticalAlignment) { "null verticalAlignment" }
+                    .align(it.height, layoutHeight)
                 IntOffset(mainAxisOffset, y)
             }
             mainAxisOffset += if (isVertical) it.height else it.width
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index d47bdc9..6b33607 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -1,6 +1,21 @@
 // Signature format: 4.0
 package androidx.tv.material3 {
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public float getIconSize();
+    method public androidx.tv.material3.ClickableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ClickableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ClickableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.AssistChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class Border {
     ctor public Border(androidx.compose.foundation.BorderStroke border, optional float inset, optional androidx.compose.ui.graphics.Shape shape);
     method public androidx.tv.material3.Border copy(optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.ui.unit.Dp? inset, optional androidx.compose.ui.graphics.Shape? shape);
@@ -150,6 +165,34 @@
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  public final class ChipKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.ClickableChipShape shape, optional androidx.tv.material3.ClickableChipColors colors, optional androidx.tv.material3.ClickableChipScale scale, optional androidx.tv.material3.ClickableChipBorder border, optional androidx.tv.material3.ClickableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.SelectableChipShape shape, optional androidx.tv.material3.SelectableChipColors colors, optional androidx.tv.material3.SelectableChipScale scale, optional androidx.tv.material3.SelectableChipBorder border, optional androidx.tv.material3.SelectableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.SelectableChipShape shape, optional androidx.tv.material3.SelectableChipColors colors, optional androidx.tv.material3.SelectableChipScale scale, optional androidx.tv.material3.SelectableChipBorder border, optional androidx.tv.material3.SelectableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.ClickableChipShape shape, optional androidx.tv.material3.ClickableChipColors colors, optional androidx.tv.material3.ClickableChipScale scale, optional androidx.tv.material3.ClickableChipBorder border, optional androidx.tv.material3.ClickableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipGlow {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipScale {
+    field public static final androidx.tv.material3.ClickableChipScale.Companion Companion;
+  }
+
+  public static final class ClickableChipScale.Companion {
+    method public androidx.tv.material3.ClickableChipScale getNone();
+    property public final androidx.tv.material3.ClickableChipScale None;
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipShape {
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableSurfaceBorder {
   }
 
@@ -279,6 +322,21 @@
   @kotlin.RequiresOptIn(message="This tv-material API is experimental and likely to change or be removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalTvMaterial3Api {
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class FilterChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder, optional androidx.tv.material3.Border selectedDisabledBorder, optional androidx.tv.material3.Border focusedSelectedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public float getIconSize();
+    method public androidx.tv.material3.SelectableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
+    method public androidx.tv.material3.SelectableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale, optional @FloatRange(from=0.0) float selectedDisabledScale, optional @FloatRange(from=0.0) float focusedSelectedDisabledScale);
+    method public androidx.tv.material3.SelectableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape, optional androidx.compose.ui.graphics.Shape selectedDisabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.FilterChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class Glow {
     ctor public Glow(long elevationColor, float elevation);
     method public androidx.tv.material3.Glow copy(optional androidx.compose.ui.graphics.Color? glowColor, optional androidx.compose.ui.unit.Dp? glowElevation);
@@ -347,6 +405,25 @@
     method public androidx.compose.ui.Modifier immersiveListItem(androidx.compose.ui.Modifier, int index);
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class InputChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipBorder border(boolean hasAvatar, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder, optional androidx.tv.material3.Border selectedDisabledBorder, optional androidx.tv.material3.Border focusedSelectedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+    method public float getAvatarSize();
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShapeWithAvatar();
+    method public float getIconSize();
+    method public androidx.tv.material3.SelectableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
+    method public androidx.tv.material3.SelectableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale, optional @FloatRange(from=0.0) float selectedDisabledScale, optional @FloatRange(from=0.0) float focusedSelectedDisabledScale);
+    method public androidx.tv.material3.SelectableChipShape shape(boolean hasAvatar, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape, optional androidx.compose.ui.graphics.Shape selectedDisabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedDisabledShape);
+    property public final float AvatarSize;
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShapeWithAvatar;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.InputChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemBorder {
   }
 
@@ -469,6 +546,27 @@
     method public void resumeAutoScroll();
   }
 
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipGlow {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipScale {
+    field public static final androidx.tv.material3.SelectableChipScale.Companion Companion;
+  }
+
+  public static final class SelectableChipScale.Companion {
+    method public androidx.tv.material3.SelectableChipScale getNone();
+    property public final androidx.tv.material3.SelectableChipScale None;
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipShape {
+  }
+
   public final class ShapeDefaults {
     method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
     method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
@@ -498,6 +596,19 @@
     property public final androidx.compose.foundation.shape.CornerBasedShape small;
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public androidx.tv.material3.ClickableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ClickableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ClickableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index d47bdc9..6b33607 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -1,6 +1,21 @@
 // Signature format: 4.0
 package androidx.tv.material3 {
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public float getIconSize();
+    method public androidx.tv.material3.ClickableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ClickableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ClickableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.AssistChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class Border {
     ctor public Border(androidx.compose.foundation.BorderStroke border, optional float inset, optional androidx.compose.ui.graphics.Shape shape);
     method public androidx.tv.material3.Border copy(optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.ui.unit.Dp? inset, optional androidx.compose.ui.graphics.Shape? shape);
@@ -150,6 +165,34 @@
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void TriStateCheckbox(androidx.compose.ui.state.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit>? onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.tv.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  public final class ChipKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.ClickableChipShape shape, optional androidx.tv.material3.ClickableChipColors colors, optional androidx.tv.material3.ClickableChipScale scale, optional androidx.tv.material3.ClickableChipBorder border, optional androidx.tv.material3.ClickableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.SelectableChipShape shape, optional androidx.tv.material3.SelectableChipColors colors, optional androidx.tv.material3.SelectableChipScale scale, optional androidx.tv.material3.SelectableChipBorder border, optional androidx.tv.material3.SelectableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.tv.material3.SelectableChipShape shape, optional androidx.tv.material3.SelectableChipColors colors, optional androidx.tv.material3.SelectableChipScale scale, optional androidx.tv.material3.SelectableChipBorder border, optional androidx.tv.material3.SelectableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional androidx.tv.material3.ClickableChipShape shape, optional androidx.tv.material3.ClickableChipColors colors, optional androidx.tv.material3.ClickableChipScale scale, optional androidx.tv.material3.ClickableChipBorder border, optional androidx.tv.material3.ClickableChipGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipGlow {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipScale {
+    field public static final androidx.tv.material3.ClickableChipScale.Companion Companion;
+  }
+
+  public static final class ClickableChipScale.Companion {
+    method public androidx.tv.material3.ClickableChipScale getNone();
+    property public final androidx.tv.material3.ClickableChipScale None;
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableChipShape {
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ClickableSurfaceBorder {
   }
 
@@ -279,6 +322,21 @@
   @kotlin.RequiresOptIn(message="This tv-material API is experimental and likely to change or be removed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalTvMaterial3Api {
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class FilterChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder, optional androidx.tv.material3.Border selectedDisabledBorder, optional androidx.tv.material3.Border focusedSelectedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public float getIconSize();
+    method public androidx.tv.material3.SelectableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
+    method public androidx.tv.material3.SelectableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale, optional @FloatRange(from=0.0) float selectedDisabledScale, optional @FloatRange(from=0.0) float focusedSelectedDisabledScale);
+    method public androidx.tv.material3.SelectableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape, optional androidx.compose.ui.graphics.Shape selectedDisabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.FilterChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class Glow {
     ctor public Glow(long elevationColor, float elevation);
     method public androidx.tv.material3.Glow copy(optional androidx.compose.ui.graphics.Color? glowColor, optional androidx.compose.ui.unit.Dp? glowElevation);
@@ -347,6 +405,25 @@
     method public androidx.compose.ui.Modifier immersiveListItem(androidx.compose.ui.Modifier, int index);
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class InputChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipBorder border(boolean hasAvatar, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder, optional androidx.tv.material3.Border selectedDisabledBorder, optional androidx.tv.material3.Border focusedSelectedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.SelectableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+    method public float getAvatarSize();
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShapeWithAvatar();
+    method public float getIconSize();
+    method public androidx.tv.material3.SelectableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
+    method public androidx.tv.material3.SelectableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale, optional @FloatRange(from=0.0) float selectedDisabledScale, optional @FloatRange(from=0.0) float focusedSelectedDisabledScale);
+    method public androidx.tv.material3.SelectableChipShape shape(boolean hasAvatar, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape, optional androidx.compose.ui.graphics.Shape selectedDisabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedDisabledShape);
+    property public final float AvatarSize;
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShapeWithAvatar;
+    property public final float IconSize;
+    field public static final androidx.tv.material3.InputChipDefaults INSTANCE;
+  }
+
   @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemBorder {
   }
 
@@ -469,6 +546,27 @@
     method public void resumeAutoScroll();
   }
 
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipGlow {
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipScale {
+    field public static final androidx.tv.material3.SelectableChipScale.Companion Companion;
+  }
+
+  public static final class SelectableChipScale.Companion {
+    method public androidx.tv.material3.SelectableChipScale getNone();
+    property public final androidx.tv.material3.SelectableChipScale None;
+  }
+
+  @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SelectableChipShape {
+  }
+
   public final class ShapeDefaults {
     method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
     method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
@@ -498,6 +596,19 @@
     property public final androidx.compose.foundation.shape.CornerBasedShape small;
   }
 
+  @androidx.tv.material3.ExperimentalTvMaterial3Api public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedDisabledBorder);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ClickableChipColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    method public float getContainerHeight();
+    method public androidx.compose.foundation.shape.RoundedCornerShape getContainerShape();
+    method public androidx.tv.material3.ClickableChipGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow);
+    method public androidx.tv.material3.ClickableChipScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedDisabledScale);
+    method public androidx.tv.material3.ClickableChipShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape);
+    property public final float ContainerHeight;
+    property public final androidx.compose.foundation.shape.RoundedCornerShape ContainerShape;
+    field public static final androidx.tv.material3.SuggestionChipDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(optional androidx.compose.ui.Modifier modifier, optional float tonalElevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.tv.material3.NonInteractiveSurfaceColors colors, optional androidx.tv.material3.Border border, optional androidx.tv.material3.Glow glow, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
     method @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void Surface(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional float tonalElevation, optional androidx.tv.material3.ToggleableSurfaceShape shape, optional androidx.tv.material3.ToggleableSurfaceColors colors, optional androidx.tv.material3.ToggleableSurfaceScale scale, optional androidx.tv.material3.ToggleableSurfaceBorder border, optional androidx.tv.material3.ToggleableSurfaceGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> content);
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipScreenshotTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipScreenshotTest.kt
new file mode 100644
index 0000000..de047a3
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipScreenshotTest.kt
@@ -0,0 +1,441 @@
+/*
+ * 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.tv.material3
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@MediumTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@OptIn(ExperimentalTvMaterial3Api::class)
+class ChipScreenshotTest(private val scheme: ColorSchemeWrapper) {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(TV_GOLDEN_MATERIAL3)
+
+    private val leadingIcon = @Composable {
+        Icon(
+            imageVector = Icons.Default.Favorite,
+            contentDescription = "Favourite icon",
+        )
+    }
+
+    private val trailingIcon = @Composable {
+        Icon(
+            imageVector = Icons.Default.Favorite,
+            contentDescription = "Favourite icon",
+        )
+    }
+
+    private val wrapperTestTag = "chipWrapper"
+
+    private val wrapperBoxModifier = Modifier
+        .testTag(wrapperTestTag)
+        .background(if (scheme.name == lightThemeName) Color.White else Color.Black)
+        .padding(20.dp)
+
+    @Test
+    fun assistChip_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                AssistChip(onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("assistChip_default_${scheme.name}")
+    }
+
+    @Test
+    fun assistChip_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                AssistChip(onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("assistChip_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun assistChip_leadingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                AssistChip(onClick = { }, leadingIcon = leadingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("assistChip_leadingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun assistChip_trailingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                AssistChip(onClick = { }, trailingIcon = trailingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("assistChip_trailingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun suggestionChip_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                SuggestionChip(onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("suggestionChip_default_${scheme.name}")
+    }
+
+    @Test
+    fun suggestionChip_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                SuggestionChip(onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("suggestionChip_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_selected_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = true, onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_selected_default_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_unselected_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = false, onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_unselected_default_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_selected_enabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = true, onClick = { }, enabled = true) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_selected_enabled_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_selected_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = true, onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_selected_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_unselected_enabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = false, onClick = { }, enabled = true) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_unselected_enabled_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_unselected_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = false, onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_unselected_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_selected_leadingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = true, onClick = { }, leadingIcon = leadingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_selected_leadingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_unselected_leadingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = false, onClick = { }, leadingIcon = leadingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_unselected_leadingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_selected_trailingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = true, onClick = { }, trailingIcon = trailingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_selected_trailingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun filterChip_unselected_trailingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                FilterChip(selected = false, onClick = { }, trailingIcon = trailingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("filterChip_unselected_trailingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_selected_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = true, onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_selected_default_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_unselected_default() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = false, onClick = { }) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_unselected_default_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_selected_enabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = true, onClick = { }, enabled = true) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_selected_enabled_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_selected_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = true, onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_selected_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_unselected_enabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = false, onClick = { }, enabled = true) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_unselected_enabled_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_unselected_disabled() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = false, onClick = { }, enabled = false) {
+                    Text(text = "Label")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_unselected_disabled_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_selected_leadingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = true, onClick = { }, leadingIcon = leadingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_selected_leadingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_unselected_leadingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = false, onClick = { }, leadingIcon = leadingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_unselected_leadingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_selected_trailingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = true, onClick = { }, trailingIcon = trailingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_selected_trailingIcon_${scheme.name}")
+    }
+
+    @Test
+    fun inputChip_unselected_trailingIcon() {
+        rule.setMaterialContent(scheme.colorScheme) {
+            Box(wrapperBoxModifier) {
+                InputChip(selected = false, onClick = { }, trailingIcon = trailingIcon) {
+                    Text(text = "Like")
+                }
+            }
+        }
+
+        assertAgainstGolden("inputChip_unselected_trailingIcon_${scheme.name}")
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(wrapperTestTag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+
+    // Provide the ColorScheme and their name parameter in a ColorSchemeWrapper.
+    // This makes sure that the default method name and the initial Scuba image generated
+    // name is as expected.
+    companion object {
+        @OptIn(ExperimentalTvMaterial3Api::class)
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun parameters() = arrayOf(
+            ColorSchemeWrapper(lightThemeName, lightColorScheme()),
+            ColorSchemeWrapper(darkThemeName, darkColorScheme()),
+        )
+    }
+
+    @OptIn(ExperimentalTvMaterial3Api::class)
+    class ColorSchemeWrapper constructor(val name: String, val colorScheme: ColorScheme) {
+        override fun toString(): String {
+            return name
+        }
+    }
+}
+
+private val lightThemeName = "lightTheme"
+private val darkThemeName = "darkTheme"
diff --git a/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipTest.kt b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipTest.kt
new file mode 100644
index 0000000..6bc7c48
--- /dev/null
+++ b/tv/tv-material/src/androidTest/java/androidx/tv/material3/ChipTest.kt
@@ -0,0 +1,663 @@
+/*
+ * 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.tv.material3
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsActions
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyInput
+import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.pressKey
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(
+    ExperimentalTestApi::class,
+    ExperimentalTvMaterial3Api::class
+)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class ChipTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun assistChip_defaultSemantics() {
+        rule.setContent {
+            Box {
+                AssistChip(
+                    modifier = Modifier.testTag(AssistChipTag),
+                    onClick = {}
+                ) { Text("Test Text") }
+            }
+        }
+
+        rule.onNodeWithTag(AssistChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun assistChip_disabledSemantics() {
+        rule.setContent {
+            Box {
+                AssistChip(
+                    modifier = Modifier.testTag(AssistChipTag),
+                    onClick = {},
+                    enabled = false
+                ) { Text("Test Text") }
+            }
+        }
+
+        rule.onNodeWithTag(AssistChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun assistChip_findByTag_andClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            Box {
+                AssistChip(
+                    modifier = Modifier.testTag(AssistChipTag),
+                    onClick = onClick
+                ) { Text("Test Text") }
+            }
+        }
+        rule.onNodeWithTag(AssistChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput {
+                pressKey(Key.DirectionCenter)
+            }
+
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun assistChip_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                AssistChip(
+                    modifier = Modifier.testTag(AssistChipTag),
+                    onClick = { enabled = false },
+                    enabled = enabled
+                ) { Text("Test Text") }
+            }
+        }
+        rule.onNodeWithTag(AssistChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            // Confirm the filterChip starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun assistChip_clickIs_independent_betweenChips() {
+        var loginCounter = 0
+        val loginChipOnClick: () -> Unit = { ++loginCounter }
+        val loginChipTag = "LoginChip"
+
+        var registerCounter = 0
+        val registerChipOnClick: () -> Unit = { ++registerCounter }
+        val registerChipTag = "RegisterChip"
+
+        rule.setContent {
+            Column {
+                AssistChip(
+                    modifier = Modifier.testTag(loginChipTag),
+                    onClick = loginChipOnClick
+                ) { Text("Login") }
+                AssistChip(
+                    modifier = Modifier.testTag(registerChipTag),
+                    onClick = registerChipOnClick
+                ) { Text("Register") }
+            }
+        }
+
+        rule.onNodeWithTag(loginChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(registerChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun filterChip_defaultSemantics() {
+        rule.setContent {
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    onClick = {},
+                    selected = false
+                ) {
+                    Text("Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(FilterChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun filterChip_disabledSemantics() {
+        rule.setContent {
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    onClick = {},
+                    enabled = false,
+                    selected = false
+                ) { Text("Test Text") }
+            }
+        }
+
+        rule.onNodeWithTag(FilterChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun filterChip_findByTag_andClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+
+        rule.setContent {
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    onClick = onClick,
+                    selected = false
+                ) { Text("Test Text") }
+            }
+        }
+        rule.onNodeWithTag(FilterChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle { Truth.assertThat(counter).isEqualTo(1) }
+    }
+
+    @Test
+    fun filterChip_showLeadingIcon_onClick() {
+        var isSelected by mutableStateOf(false)
+        rule.setContent {
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    selected = isSelected,
+                    onClick = { isSelected = true },
+                    leadingIcon = {
+                        Box(
+                            modifier = Modifier
+                                .testTag(FilterChipLeadingContentTag)
+                                .size(FilterChipDefaults.IconSize),
+                        )
+                    }
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(FilterChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.waitUntil { isSelected }
+        rule.onNodeWithTag(FilterChipLeadingContentTag, useUnmergedTree = true).assertIsDisplayed()
+    }
+
+    @Test
+    fun filterChip_showCustomIcon_onClick() {
+        var isSelected by mutableStateOf(false)
+        rule.setContent {
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    selected = isSelected,
+                    leadingIcon = {
+                        Box(
+                            modifier = Modifier
+                                .size(DefaultIconSize)
+                                .semantics { contentDescription = "Add Icon" }
+                        )
+                    },
+                    onClick = { isSelected = true }
+                ) {
+                    Text(text = "Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(FilterChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.onNodeWithContentDescription("Filter Selected").assertDoesNotExist()
+        rule.onNodeWithContentDescription("Add Icon").assertIsDisplayed()
+    }
+
+    @Test
+    fun filterChip_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                FilterChip(
+                    modifier = Modifier.testTag(FilterChipTag),
+                    onClick = { enabled = false },
+                    enabled = enabled,
+                    selected = true
+                ) {
+                    Text("Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(FilterChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            // Confirm the filterChip starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun filterChip_clickIs_independent_betweenChips() {
+        var loginCounter = 0
+        val loginChipOnClick: () -> Unit = { ++loginCounter }
+        val loginChipTag = "LoginChip"
+
+        var registerCounter = 0
+        val registerChpOnClick: () -> Unit = { ++registerCounter }
+        val registerChipTag = "RegisterChip"
+
+        rule.setContent {
+            Column {
+                FilterChip(
+                    modifier = Modifier.testTag(loginChipTag),
+                    onClick = loginChipOnClick,
+                    selected = true
+                ) { Text("Login") }
+                FilterChip(
+                    modifier = Modifier.testTag(registerChipTag),
+                    onClick = registerChpOnClick,
+                    selected = true
+                ) { Text("Register") }
+            }
+        }
+
+        rule.onNodeWithTag(loginChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(registerChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun inputChip_defaultSemantics() {
+        rule.setContent {
+            Box {
+                InputChip(
+                    modifier = Modifier.testTag(InputChipTag),
+                    onClick = {},
+                    selected = false
+                ) {
+                    Text("Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(InputChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun inputChip_disabledSemantics() {
+        rule.setContent {
+            Box {
+                InputChip(
+                    modifier = Modifier.testTag(InputChipTag),
+                    onClick = {},
+                    enabled = false,
+                    selected = false
+                ) {
+                    Text("Test Text")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(InputChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun inputChip_findByTag_andClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+        val text = "Test Text"
+
+        rule.setContent {
+            Box {
+                InputChip(
+                    modifier = Modifier.testTag(InputChipTag),
+                    onClick = onClick,
+                    selected = false
+                ) {
+                    Text(text)
+                }
+            }
+        }
+        rule.onNodeWithTag(InputChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun inputChip_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                InputChip(
+                    modifier = Modifier.testTag(InputChipTag),
+                    onClick = { enabled = false },
+                    enabled = enabled,
+                    selected = true
+                ) {
+                    Text("Test Text")
+                }
+            }
+        }
+        rule.onNodeWithTag(InputChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            // Confirm the filterChip starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun inputChip_clickIs_independent_betweenChips() {
+        var loginCounter = 0
+        val loginChipOnClick: () -> Unit = { ++loginCounter }
+        val loginChipTag = "LoginChip"
+        val loginChipText = "Login"
+
+        var registerCounter = 0
+        val registerChipOnClick: () -> Unit = { ++registerCounter }
+        val registerChipTag = "RegisterChip"
+        val registerChipText = "Register"
+
+        rule.setContent {
+            Column {
+                InputChip(
+                    modifier = Modifier.testTag(loginChipTag),
+                    onClick = loginChipOnClick,
+                    selected = true
+                ) {
+                    Text(loginChipText)
+                }
+                InputChip(
+                    modifier = Modifier.testTag(registerChipTag),
+                    onClick = registerChipOnClick,
+                    selected = true
+                ) {
+                    Text(registerChipText)
+                }
+            }
+        }
+
+        rule.onNodeWithTag(loginChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(registerChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun suggestionChip_defaultSemantics() {
+        rule.setContent {
+            Box {
+                SuggestionChip(
+                    modifier = Modifier.testTag(SuggestionChipTag),
+                    onClick = {}
+                ) {
+                    Text("mvTvSelectableChip")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(SuggestionChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsEnabled()
+    }
+
+    @Test
+    fun suggestionChip_disabledSemantics() {
+        rule.setContent {
+            Box {
+                SuggestionChip(
+                    modifier = Modifier.testTag(SuggestionChipTag),
+                    onClick = {},
+                    enabled = false
+                ) {
+                    Text("mvTvSelectableChip")
+                }
+            }
+        }
+
+        rule.onNodeWithTag(SuggestionChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun suggestionChip_findByTag_andClick() {
+        var counter = 0
+        val onClick: () -> Unit = { ++counter }
+        val text = "myTvSuggestionChip"
+
+        rule.setContent {
+            Box {
+                SuggestionChip(
+                    modifier = Modifier.testTag(SuggestionChipTag),
+                    onClick = onClick
+                ) {
+                    Text(text = text)
+                }
+            }
+        }
+        rule.onNodeWithTag(SuggestionChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+        rule.runOnIdle {
+            Truth.assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun suggestionChip_canBeDisabled() {
+        rule.setContent {
+            var enabled by remember { mutableStateOf(true) }
+            Box {
+                SuggestionChip(
+                    modifier = Modifier.testTag(SuggestionChipTag),
+                    onClick = { enabled = false },
+                    enabled = enabled
+                ) {
+                    Text("Hello")
+                }
+            }
+        }
+        rule.onNodeWithTag(SuggestionChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            // Confirm the chip starts off enabled, with a click action
+            .assertHasClickAction()
+            .assertIsEnabled()
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+            // Then confirm it's disabled with click action after clicking it
+            .assertHasClickAction()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun suggestionChip_clickIs_independent_betweenChips() {
+        var loginCounter = 0
+        val loginChipOnClick: () -> Unit = { ++loginCounter }
+        val loginChipTag = "LoginChip"
+        val loginChipText = "Login"
+
+        var registerCounter = 0
+        val registerChipOnClick: () -> Unit = { ++registerCounter }
+        val registerChipTag = "RegisterChip"
+        val registerChipText = "Register"
+
+        rule.setContent {
+            Column {
+                SuggestionChip(
+                    modifier = Modifier.testTag(loginChipTag),
+                    onClick = loginChipOnClick
+                ) {
+                    Text(text = loginChipText)
+                }
+
+                SuggestionChip(
+                    modifier = Modifier.testTag(registerChipTag),
+                    onClick = registerChipOnClick
+                ) {
+                    Text(text = registerChipText)
+                }
+            }
+        }
+
+        rule.onNodeWithTag(loginChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(registerChipTag)
+            .performSemanticsAction(SemanticsActions.RequestFocus)
+            .performKeyInput { pressKey(Key.DirectionCenter) }
+
+        rule.runOnIdle {
+            Truth.assertThat(loginCounter).isEqualTo(1)
+            Truth.assertThat(registerCounter).isEqualTo(1)
+        }
+    }
+}
+
+private const val AssistChipTag = "AssistChipTag"
+private const val AssistChipLabelTag = "AssistChipLabel"
+private const val AssistChipLeadingIconTag = "AssistChipLeadingIcon"
+
+private const val FilterChipTag = "FilterChip"
+private const val FilterChipLabelTag = "FilterChipLabel"
+private const val FilterChipLeadingContentTag = "FilterChipLeadingContent"
+
+private const val InputChipTag = "InputChip"
+private const val InputChipLabelTag = "InputChipLabel"
+private const val InputChipAvatarTag = "InputChipAvatar"
+private const val InputChipLeadingContentTag = "InputChipLeadingContent"
+private const val InputChipTrailingContentTag = "InputChipTrailingContent"
+
+private const val SuggestionChipTag = "SuggestionChip"
+private const val SuggestionChipLabelTag = "SuggestionChipLabel"
+
+private val DefaultIconSize = 24.dp
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/Chip.kt b/tv/tv-material/src/main/java/androidx/tv/material3/Chip.kt
new file mode 100644
index 0000000..8833042
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/Chip.kt
@@ -0,0 +1,1397 @@
+/*
+ * 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.tv.material3
+
+import androidx.annotation.FloatRange
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.NonRestartableComposable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Material Design assist chip
+ *
+ * Chips help people enter information, make selections, filter content, or trigger actions. Chips
+ * can show multiple interactive elements together in the same area, such as a list of selectable
+ * movie times, or a series of email contacts
+ *
+ * Assist chips represent smart or automated actions that can span multiple apps, such as opening a
+ * calendar event from the home screen. Assist chips function as though the user asked an assistant
+ * to complete the action. They should appear dynamically and contextually in a UI
+ *
+ * @param onClick called when this chip is clicked
+ * @param modifier the [Modifier] to be applied to this chip
+ * @param enabled controls the enabled state of this chip. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services
+ * @param onLongClick callback to be called when the surface is long clicked (long-pressed)
+ * @param leadingIcon optional icon at the start of the chip, preceding the [content] text
+ * @param trailingIcon optional icon at the end of the chip
+ * @param shape Defines the Chip's shape
+ * @param colors Color to be used on background and content of the chip
+ * @param scale Defines size of the chip relative to its original size
+ * @param border Defines a border around the chip
+ * @param glow Shadow to be shown behind the chip
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this chip. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this chip in different states
+ * @param content for this chip, ideally a Text composable
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun AssistChip(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    onLongClick: (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    shape: ClickableChipShape = AssistChipDefaults.shape(),
+    colors: ClickableChipColors = AssistChipDefaults.colors(),
+    scale: ClickableChipScale = AssistChipDefaults.scale(),
+    border: ClickableChipBorder = AssistChipDefaults.border(),
+    glow: ClickableChipGlow = AssistChipDefaults.glow(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable () -> Unit
+) {
+    ClickableChip(
+        modifier = modifier,
+        onClick = onClick,
+        enabled = enabled,
+        onLongClick = onLongClick,
+        label = content,
+        labelTextStyle = MaterialTheme.typography.labelLarge,
+        leadingIcon = leadingIcon,
+        trailingIcon = trailingIcon,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow,
+        minHeight = AssistChipDefaults.ContainerHeight,
+        paddingValues = chipPadding(
+            hasAvatar = false,
+            hasLeadingIcon = leadingIcon != null,
+            hasTrailingIcon = trailingIcon != null
+        ),
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * Material Design filter chip
+ *
+ * Chips help people enter information, make selections, filter content, or trigger actions. Chips
+ * can show multiple interactive elements together in the same area, such as a list of selectable
+ * movie times, or a series of email contacts
+ *
+ * Filter chips use tags or descriptive words to filter content. They can be a good alternative to
+ * toggle buttons or checkboxes
+ *
+ * Tapping on a filter chip toggles its selection state. A selection state [leadingIcon] can be
+ * provided (e.g. a checkmark) to be appended at the starting edge of the chip's label
+ *
+ * @param selected whether this chip is selected or not
+ * @param onClick called when this chip is clicked
+ * @param modifier the [Modifier] to be applied to this chip
+ * @param enabled controls the enabled state of this chip. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services
+ * @param onLongClick callback to be called when the surface is long clicked (long-pressed)
+ * @param leadingIcon optional icon at the start of the chip, preceding the [content] text
+ * @param trailingIcon optional icon at the end of the chip
+ * @param shape Defines the Chip's shape
+ * @param colors Color to be used on background and content of the chip
+ * @param scale Defines size of the chip relative to its original size
+ * @param border Defines a border around the chip
+ * @param glow Shadow to be shown behind the chip
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this chip. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this chip in different states
+ * @param content for this chip, ideally a Text composable
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun FilterChip(
+    selected: Boolean,
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    onLongClick: (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    shape: SelectableChipShape = FilterChipDefaults.shape(),
+    colors: SelectableChipColors = FilterChipDefaults.colors(),
+    scale: SelectableChipScale = FilterChipDefaults.scale(),
+    border: SelectableChipBorder = FilterChipDefaults.border(),
+    glow: SelectableChipGlow = FilterChipDefaults.glow(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable () -> Unit
+) {
+    SelectableChip(
+        selected = selected,
+        modifier = modifier,
+        onClick = onClick,
+        enabled = enabled,
+        onLongClick = onLongClick,
+        label = content,
+        labelTextStyle = MaterialTheme.typography.labelLarge,
+        leadingIcon = leadingIcon,
+        avatar = null,
+        trailingIcon = trailingIcon,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow,
+        minHeight = FilterChipDefaults.ContainerHeight,
+        paddingValues = chipPadding(
+            hasAvatar = false,
+            hasLeadingIcon = leadingIcon != null,
+            hasTrailingIcon = trailingIcon != null
+        ),
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * Chips help people enter information, make selections, filter content, or trigger actions. Chips
+ * can show multiple interactive elements together in the same area, such as a list of selectable
+ * movie times, or a series of email contacts
+ *
+ * Input chips represent discrete pieces of information entered by a user
+ *
+ * An Input Chip can have a leading icon or an avatar at its start. In case both are provided, the
+ * avatar will take precedence and will be displayed
+ *
+ * @param selected whether this chip is selected or not
+ * @param onClick called when this chip is clicked
+ * @param modifier the [Modifier] to be applied to this chip
+ * @param enabled controls the enabled state of this chip. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services
+ * @param onLongClick callback to be called when the surface is long clicked (long-pressed)
+ * @param leadingIcon optional icon at the start of the chip, preceding the [content] text
+ * @param avatar optional avatar at the start of the chip, preceding the [content] text
+ * @param trailingIcon optional icon at the end of the chip
+ * @param shape Defines the Chip's shape
+ * @param colors Color to be used on background and content of the chip
+ * @param scale Defines size of the chip relative to its original size
+ * @param border Defines a border around the chip
+ * @param glow Shadow to be shown behind the chip
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this chip. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this chip in different states
+ * @param content for this chip, ideally a Text composable
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun InputChip(
+    selected: Boolean,
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    onLongClick: (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    avatar: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    shape: SelectableChipShape = InputChipDefaults.shape(hasAvatar = avatar != null),
+    colors: SelectableChipColors = InputChipDefaults.colors(),
+    scale: SelectableChipScale = InputChipDefaults.scale(),
+    border: SelectableChipBorder = InputChipDefaults.border(hasAvatar = avatar != null),
+    glow: SelectableChipGlow = InputChipDefaults.glow(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable () -> Unit
+) {
+    SelectableChip(
+        selected = selected,
+        modifier = modifier,
+        onClick = onClick,
+        enabled = enabled,
+        onLongClick = onLongClick,
+        label = content,
+        labelTextStyle = MaterialTheme.typography.labelLarge,
+        leadingIcon = leadingIcon,
+        avatar = avatar,
+        trailingIcon = trailingIcon,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow,
+        minHeight = InputChipDefaults.ContainerHeight,
+        paddingValues = chipPadding(
+            hasAvatar = avatar != null,
+            hasLeadingIcon = leadingIcon != null,
+            hasTrailingIcon = trailingIcon != null
+        ),
+        interactionSource = interactionSource
+    )
+}
+
+/**
+ * Material Design suggestion chip
+ *
+ * Chips help people enter information, make selections, filter content, or trigger actions. Chips
+ * can show multiple interactive elements together in the same area, such as a list of selectable
+ * movie times, or a series of email contacts
+ *
+ * Suggestion chips help narrow a user's intent by presenting dynamically generated suggestions,
+ * such as possible responses or search filters
+ *
+ * @param onClick called when this chip is clicked
+ * @param modifier the [Modifier] to be applied to this chip
+ * @param enabled controls the enabled state of this chip. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services
+ * @param onLongClick callback to be called when the surface is long clicked (long-pressed)
+ * @param shape Defines the Chip's shape
+ * @param colors Color to be used on background and content of the chip
+ * @param scale Defines size of the chip relative to its original size
+ * @param border Defines a border around the chip
+ * @param glow Shadow to be shown behind the chip
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this chip. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this chip in different states
+ * @param content content for this chip, ideally a Text composable
+ */
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+fun SuggestionChip(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    onLongClick: (() -> Unit)? = null,
+    shape: ClickableChipShape = SuggestionChipDefaults.shape(),
+    colors: ClickableChipColors = SuggestionChipDefaults.colors(),
+    scale: ClickableChipScale = SuggestionChipDefaults.scale(),
+    border: ClickableChipBorder = SuggestionChipDefaults.border(),
+    glow: ClickableChipGlow = SuggestionChipDefaults.glow(),
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    content: @Composable () -> Unit
+) {
+    ClickableChip(
+        modifier = modifier,
+        onClick = onClick,
+        enabled = enabled,
+        onLongClick = onLongClick,
+        label = content,
+        labelTextStyle = MaterialTheme.typography.labelLarge,
+        leadingIcon = null,
+        trailingIcon = null,
+        shape = shape,
+        colors = colors,
+        scale = scale,
+        border = border,
+        glow = glow,
+        minHeight = SuggestionChipDefaults.ContainerHeight,
+        paddingValues = chipPadding(
+            hasAvatar = false,
+            hasLeadingIcon = false,
+            hasTrailingIcon = false
+        ),
+        interactionSource = interactionSource
+    )
+}
+
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+private fun ClickableChip(
+    modifier: Modifier,
+    onClick: () -> Unit,
+    onLongClick: (() -> Unit)?,
+    enabled: Boolean,
+    label: @Composable () -> Unit,
+    labelTextStyle: TextStyle,
+    leadingIcon: @Composable (() -> Unit)?,
+    trailingIcon: @Composable (() -> Unit)?,
+    shape: ClickableChipShape,
+    colors: ClickableChipColors,
+    scale: ClickableChipScale,
+    border: ClickableChipBorder,
+    glow: ClickableChipGlow,
+    minHeight: Dp,
+    paddingValues: PaddingValues,
+    interactionSource: MutableInteractionSource
+) {
+    Surface(
+        modifier = modifier.semantics { role = Role.Button },
+        onClick = onClick,
+        onLongClick = onLongClick,
+        enabled = enabled,
+        shape = shape.toClickableSurfaceShape(),
+        colors = colors.toClickableSurfaceColors(),
+        scale = scale.toClickableSurfaceScale(),
+        border = border.toClickableSurfaceBorder(),
+        glow = glow.toClickableSurfaceGlow(),
+        interactionSource = interactionSource
+    ) {
+        ChipContent(
+            label = label,
+            labelTextStyle = labelTextStyle,
+            leadingIcon = leadingIcon,
+            avatar = null,
+            trailingIcon = trailingIcon,
+            minHeight = minHeight,
+            paddingValues = paddingValues
+        )
+    }
+}
+
+@ExperimentalTvMaterial3Api
+@NonRestartableComposable
+@Composable
+private fun SelectableChip(
+    selected: Boolean,
+    modifier: Modifier,
+    onClick: () -> Unit,
+    onLongClick: (() -> Unit)?,
+    enabled: Boolean,
+    label: @Composable () -> Unit,
+    labelTextStyle: TextStyle,
+    leadingIcon: @Composable (() -> Unit)?,
+    avatar: @Composable (() -> Unit)?,
+    trailingIcon: @Composable (() -> Unit)?,
+    shape: SelectableChipShape,
+    colors: SelectableChipColors,
+    scale: SelectableChipScale,
+    border: SelectableChipBorder,
+    glow: SelectableChipGlow,
+    minHeight: Dp,
+    paddingValues: PaddingValues,
+    interactionSource: MutableInteractionSource
+) {
+    Surface(
+        checked = selected,
+        onCheckedChange = { onClick() },
+        modifier = modifier.semantics { role = Role.Checkbox },
+        enabled = enabled,
+        onLongClick = onLongClick,
+        shape = shape.toToggleableSurfaceShape(),
+        colors = colors.toToggleableSurfaceColors(),
+        scale = scale.toToggleableSurfaceScale(),
+        border = border.toToggleableSurfaceBorder(),
+        glow = glow.toToggleableSurfaceGlow(),
+        interactionSource = interactionSource
+    ) {
+        ChipContent(
+            label = label,
+            labelTextStyle = labelTextStyle,
+            leadingIcon = leadingIcon,
+            avatar = avatar,
+            trailingIcon = trailingIcon,
+            minHeight = minHeight,
+            paddingValues = paddingValues
+        )
+    }
+}
+
+@Composable
+private fun ChipContent(
+    label: @Composable () -> Unit,
+    labelTextStyle: TextStyle,
+    leadingIcon: @Composable (() -> Unit)?,
+    avatar: @Composable (() -> Unit)?,
+    trailingIcon: @Composable (() -> Unit)?,
+    minHeight: Dp,
+    paddingValues: PaddingValues
+) {
+
+    Row(
+        Modifier
+            .defaultMinSize(minHeight = minHeight)
+            .padding(paddingValues),
+        horizontalArrangement = Arrangement.Start,
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        androidx.compose.animation.AnimatedVisibility(visible = avatar != null) {
+            Row {
+                avatar?.invoke()
+                Spacer(Modifier.width(HorizontalElementsPadding))
+            }
+        }
+        androidx.compose.animation.AnimatedVisibility(visible = leadingIcon != null) {
+            Row {
+                leadingIcon?.invoke()
+                Spacer(Modifier.width(HorizontalElementsPadding))
+            }
+        }
+        CompositionLocalProvider(
+            LocalTextStyle provides labelTextStyle,
+            content = label
+        )
+        trailingIcon?.let { nnTrailingIcon ->
+            Spacer(Modifier.width(HorizontalElementsPadding))
+            nnTrailingIcon()
+        }
+    }
+}
+
+/**
+ * Returns the [PaddingValues] for any TV chip component
+ */
+private fun chipPadding(
+    hasAvatar: Boolean,
+    hasLeadingIcon: Boolean,
+    hasTrailingIcon: Boolean
+): PaddingValues {
+    val start = if (hasAvatar) 4.dp else if (hasLeadingIcon) 12.dp else 16.dp
+    val end = if (hasTrailingIcon) 12.dp else 16.dp
+    val vertical = if (hasAvatar) 4.dp else 8.dp
+    return PaddingValues(
+        start = start,
+        end = end,
+        top = vertical,
+        bottom = vertical
+    )
+}
+
+/**
+ * Contains the default values used by [AssistChip]
+ */
+@ExperimentalTvMaterial3Api
+object AssistChipDefaults {
+    /**
+     * The height applied to an assist chip.
+     * Note that you can override it by applying Modifier.height directly on a chip.
+     */
+    val ContainerHeight = 36.dp
+
+    /**
+     * The size of an Assist chip icon
+     */
+    val IconSize = 18.dp
+
+    /**
+     * The default [Shape] applied to an assist chip
+     */
+    val ContainerShape = RoundedCornerShape(8.dp)
+
+    private const val DisabledBackgroundColorOpacity = 0.2f
+    private const val DisabledContentColorOpacity = 0.8f
+
+    /**
+     * Creates a [ClickableChipShape] that represents the default container shapes used in an
+     * [AssistChip]
+     *
+     * @param shape the shape used when the Chip is enabled, and has no other [Interaction]s
+     * @param focusedShape the shape used when the Chip is enabled and focused
+     * @param pressedShape the shape used when the Chip is enabled pressed
+     * @param disabledShape the shape used when the Chip is not enabled
+     * @param focusedDisabledShape the shape used when the Chip is not enabled and focused
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape
+    ) = ClickableChipShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+
+    /**
+     * Creates a [ClickableChipColors] that represents the default container and content colors
+     * used in an [AssistChip]
+     *
+     * @param containerColor the container color of this Chip when enabled
+     * @param contentColor the content color of this Chip when enabled
+     * @param focusedContainerColor the container color of this Chip when enabled and focused
+     * @param focusedContentColor the content color of this Chip when enabled and focused
+     * @param pressedContainerColor the container color of this Chip when enabled and pressed
+     * @param pressedContentColor the content color of this Chip when enabled and pressed
+     * @param disabledContainerColor the container color of this Chip when not enabled
+     * @param disabledContentColor the content color of this Chip when not enabled
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        pressedContentColor: Color = MaterialTheme.colorScheme.surface,
+        disabledContainerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(
+            alpha = DisabledBackgroundColorOpacity
+        ),
+        disabledContentColor: Color = MaterialTheme.colorScheme.border.copy(
+            alpha = DisabledContentColorOpacity
+        ),
+    ) = ClickableChipColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+    )
+
+    /**
+     * Creates a [ClickableChipScale] that represents the default scaleFactors used in an
+     * [AssistChip].
+     * scaleFactors are used to modify the size of a composable in different [Interaction]
+     * states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc
+     *
+     * @param scale the scaleFactor to be used for this Chip when enabled
+     * @param focusedScale the scaleFactor to be used for this Chip when focused
+     * @param pressedScale the scaleFactor to be used for this Chip when pressed
+     * @param disabledScale the scaleFactor to be used for this Chip when disabled
+     * @param focusedDisabledScale the scaleFactor to be used for this Chip when disabled and
+     * focused
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
+    ) = ClickableChipScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+
+    /**
+     * Creates a [ClickableChipBorder] that represents the default [Border]s applied on an
+     * AssistChip in different [Interaction] states.
+     *
+     * @param border the [Border] to be used for this Chip when enabled
+     * @param focusedBorder the [Border] to be used for this Chip when focused
+     * @param pressedBorder the [Border] to be used for this Chip when pressed
+     * @param disabledBorder the [Border] to be used for this Chip when disabled
+     * @param focusedDisabledBorder the [Border] to be used for this Chip when disabled and
+     * focused
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.border
+            ),
+            shape = ContainerShape
+        ),
+        focusedBorder: Border = Border.None,
+        pressedBorder: Border = focusedBorder,
+        disabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.surfaceVariant
+            ),
+            shape = ContainerShape
+        ),
+        focusedDisabledBorder: Border = border
+    ) = ClickableChipBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+
+    /**
+     * Creates a [ClickableChipGlow] that represents the default [Glow]s used in an [AssistChip]
+     *
+     * @param glow the Glow behind this Button when enabled
+     * @param focusedGlow the Glow behind this Button when focused
+     * @param pressedGlow the Glow behind this Button when pressed
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow
+    ) = ClickableChipGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
+
+/**
+ * Contains the default values used by [FilterChip].
+ */
+@ExperimentalTvMaterial3Api
+object FilterChipDefaults {
+    /**
+     * The height applied to a filter chip.
+     * Note that you can override it by applying Modifier.height directly on a chip.
+     */
+    val ContainerHeight = 36.dp
+
+    /**
+     * The size of a Filter chip icon
+     */
+    val IconSize = 18.dp
+
+    /**
+     * The default [Shape] applied to a filter chip
+     */
+    val ContainerShape = RoundedCornerShape(8.dp)
+
+    private const val SelectedBackgroundColorOpacity = 0.4f
+    private const val DisabledBackgroundColorOpacity = 0.2f
+    private const val DisabledContentColorOpacity = 0.8f
+
+    /**
+     * Creates a [SelectableChipShape] that represents the default container shapes used in a
+     * [FilterChip]
+     *
+     * @param shape the shape used when the Chip is enabled, and has no other [Interaction]s
+     * @param focusedShape the shape used when the Chip is enabled and focused
+     * @param pressedShape the shape used when the Chip is enabled and pressed
+     * @param selectedShape the shape used when the Chip is enabled and selected
+     * @param disabledShape the shape used when the Chip is not enabled
+     * @param focusedSelectedShape the shape used when the Chip is enabled, focused and selected
+     * @param focusedDisabledShape the shape used when the Chip is not enabled and focused
+     * @param pressedSelectedShape the shape used when the Chip is enabled, pressed and selected
+     * @param selectedDisabledShape the shape used when the Chip is not enabled and selected
+     * @param focusedSelectedDisabledShape the shape used when the Chip is not enabled, focused
+     * and selected
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        selectedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedSelectedShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape,
+        pressedSelectedShape: Shape = shape,
+        selectedDisabledShape: Shape = disabledShape,
+        focusedSelectedDisabledShape: Shape = disabledShape
+    ) = SelectableChipShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        selectedShape = selectedShape,
+        disabledShape = disabledShape,
+        focusedSelectedShape = focusedSelectedShape,
+        focusedDisabledShape = focusedDisabledShape,
+        pressedSelectedShape = pressedSelectedShape,
+        selectedDisabledShape = selectedDisabledShape,
+        focusedSelectedDisabledShape = focusedSelectedDisabledShape
+    )
+
+    /**
+     * Creates a [SelectableChipColors] that represents the default container and content colors
+     * used in a [FilterChip]
+     *
+     * @param containerColor the container color used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param contentColor the content color used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedContainerColor the container color used when the Chip is enabled and focused
+     * @param focusedContentColor the content color used when the Chip is enabled and focused
+     * @param pressedContainerColor the container color used when the Chip is enabled and pressed
+     * @param pressedContentColor the content color used when the Chip is enabled and pressed
+     * @param selectedContainerColor the container color used when the Chip is enabled and selected
+     * @param selectedContentColor the content color used when the Chip is enabled and selected
+     * @param disabledContainerColor the container color used when the Chip is not enabled
+     * @param disabledContentColor the content color used when the Chip is not enabled
+     * @param focusedSelectedContainerColor the container color used when the Chip is enabled,
+     * focused and selected
+     * @param focusedSelectedContentColor the content color used when the Chip is enabled,
+     * focused and selected
+     * @param pressedSelectedContainerColor the container color used when the Chip is enabled,
+     * pressed and selected
+     * @param pressedSelectedContentColor the content color used when the Chip is enabled,
+     * pressed and selected
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        pressedContentColor: Color = MaterialTheme.colorScheme.surface,
+        selectedContainerColor: Color = MaterialTheme.colorScheme.secondaryContainer.copy(
+            alpha = SelectedBackgroundColorOpacity
+        ),
+        selectedContentColor: Color = MaterialTheme.colorScheme.onSecondaryContainer,
+        disabledContainerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(
+            alpha = DisabledBackgroundColorOpacity
+        ),
+        disabledContentColor: Color = MaterialTheme.colorScheme.border.copy(
+            alpha = DisabledContentColorOpacity
+        ),
+        focusedSelectedContainerColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
+        focusedSelectedContentColor: Color = MaterialTheme.colorScheme.onPrimary,
+        pressedSelectedContainerColor: Color = MaterialTheme.colorScheme.secondary,
+        pressedSelectedContentColor: Color = MaterialTheme.colorScheme.onSecondary,
+    ) = SelectableChipColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        selectedContainerColor = selectedContainerColor,
+        selectedContentColor = selectedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+        focusedSelectedContainerColor = focusedSelectedContainerColor,
+        focusedSelectedContentColor = focusedSelectedContentColor,
+        pressedSelectedContainerColor = pressedSelectedContainerColor,
+        pressedSelectedContentColor = pressedSelectedContentColor,
+    )
+
+    /**
+     * Creates a [SelectableChipScale] that represents the default scaleFactors used in a
+     * [FilterChip]. scaleFactors are used to modify the size of a composable in different
+     * [Interaction] states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc
+     *
+     * @param scale the scaleFactor used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedScale the scaleFactor used when the Chip is enabled and focused
+     * @param pressedScale the scaleFactor used when the Chip is enabled and pressed
+     * @param selectedScale the scaleFactor used when the Chip is enabled and selected
+     * @param disabledScale the scaleFactor used when the Chip is not enabled
+     * @param focusedSelectedScale the scaleFactor used when the Chip is enabled, focused and
+     * selected
+     * @param focusedDisabledScale the scaleFactor used when the Chip is not enabled and
+     * focused
+     * @param pressedSelectedScale the scaleFactor used when the Chip is enabled, pressed and
+     * selected
+     * @param selectedDisabledScale the scaleFactor used when the Chip is not enabled and
+     * selected
+     * @param focusedSelectedDisabledScale the scaleFactor used when the Chip is not enabled,
+     * focused and selected
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) selectedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedSelectedScale: Float = focusedScale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale,
+        @FloatRange(from = 0.0) pressedSelectedScale: Float = scale,
+        @FloatRange(from = 0.0) selectedDisabledScale: Float = disabledScale,
+        @FloatRange(from = 0.0) focusedSelectedDisabledScale: Float = disabledScale
+    ) = SelectableChipScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        selectedScale = selectedScale,
+        disabledScale = disabledScale,
+        focusedSelectedScale = focusedSelectedScale,
+        focusedDisabledScale = focusedDisabledScale,
+        pressedSelectedScale = pressedSelectedScale,
+        selectedDisabledScale = selectedDisabledScale,
+        focusedSelectedDisabledScale = focusedSelectedDisabledScale
+    )
+
+    /**
+     * Creates a [SelectableChipBorder] that represents the default [Border]s applied on a
+     * [FilterChip] in different [Interaction] states
+     *
+     * @param border the [Border] used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedBorder the [Border] used when the Chip is enabled and focused
+     * @param pressedBorder the [Border] used when the Chip is enabled and pressed
+     * @param selectedBorder the [Border] used when the Chip is enabled and selected
+     * @param disabledBorder the [Border] used when the Chip is not enabled
+     * @param focusedSelectedBorder the [Border] used when the Chip is enabled, focused and
+     * selected
+     * @param focusedDisabledBorder the [Border] used when the Chip is not enabled and focused
+     * @param pressedSelectedBorder the [Border] used when the Chip is enabled, pressed and
+     * selected
+     * @param selectedDisabledBorder the [Border] used when the Chip is not enabled and
+     * selected
+     * @param focusedSelectedDisabledBorder the [Border] used when the Chip is not enabled,
+     * focused and selected
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.border
+            ),
+            shape = ContainerShape
+        ),
+        focusedBorder: Border = Border.None,
+        pressedBorder: Border = focusedBorder,
+        selectedBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.secondary
+            ),
+            shape = ContainerShape
+        ),
+        disabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.surfaceVariant
+            ),
+            shape = ContainerShape
+        ),
+        focusedSelectedBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.1.dp,
+                color = MaterialTheme.colorScheme.onPrimaryContainer
+            ),
+            shape = ContainerShape
+        ),
+        focusedDisabledBorder: Border = border,
+        pressedSelectedBorder: Border = Border.None,
+        selectedDisabledBorder: Border = Border.None,
+        focusedSelectedDisabledBorder: Border = border
+    ) = SelectableChipBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        selectedBorder = selectedBorder,
+        disabledBorder = disabledBorder,
+        focusedSelectedBorder = focusedSelectedBorder,
+        focusedDisabledBorder = focusedDisabledBorder,
+        pressedSelectedBorder = pressedSelectedBorder,
+        selectedDisabledBorder = selectedDisabledBorder,
+        focusedSelectedDisabledBorder = focusedSelectedDisabledBorder,
+    )
+
+    /**
+     * Creates a [SelectableChipGlow] that represents the default [Glow]s used in a [FilterChip]
+     *
+     * @param glow the [Glow] used when the Chip is enabled, and has no other [Interaction]s
+     * @param focusedGlow the [Glow] used when the Chip is enabled and focused
+     * @param pressedGlow the [Glow] used when the Chip is enabled and pressed
+     * @param selectedGlow the [Glow] used when the Chip is enabled and selected
+     * @param focusedSelectedGlow the [Glow] used when the Chip is enabled, focused and selected
+     * @param pressedSelectedGlow the [Glow] used when the Chip is enabled, pressed and selected
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow,
+        selectedGlow: Glow = glow,
+        focusedSelectedGlow: Glow = focusedGlow,
+        pressedSelectedGlow: Glow = glow
+    ) = SelectableChipGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow,
+        selectedGlow = selectedGlow,
+        focusedSelectedGlow = focusedSelectedGlow,
+        pressedSelectedGlow = pressedSelectedGlow
+    )
+}
+
+/**
+ * Contains the default values used by [InputChip].
+ */
+@ExperimentalTvMaterial3Api
+object InputChipDefaults {
+    /**
+     * The height applied for an input chip.
+     * Note that you can override it by applying Modifier.height directly on a chip.
+     */
+    val ContainerHeight = 36.dp
+
+    /**
+     * The size of an Input chip icon
+     */
+    val IconSize = 18.dp
+
+    /**
+     * The size of an Input chip avatar
+     */
+    val AvatarSize = 28.dp
+
+    /**
+     * The default [Shape] applied to an input chip
+     */
+    val ContainerShape = RoundedCornerShape(8.dp)
+
+    /**
+     * The default [Shape] applied to an input chip with avatar
+     */
+    val ContainerShapeWithAvatar = RoundedCornerShape(36.dp)
+
+    private const val SelectedBackgroundColorOpacity = 0.4f
+    private const val DisabledBackgroundColorOpacity = 0.2f
+    private const val DisabledContentColorOpacity = 0.8f
+
+    /**
+     * Creates a [SelectableChipShape] that represents the default container shapes used in an
+     * [InputChip]
+     *
+     * @param hasAvatar changes the default shape based on whether the avatar composable is not
+     * null in the Chip
+     * @param shape the shape used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedShape the shape used when the Chip is enabled and focused
+     * @param pressedShape the shape used when the Chip is enabled and pressed
+     * @param selectedShape the shape used when the Chip is enabled and selected
+     * @param disabledShape the shape used when the Chip is not enabled
+     * @param focusedSelectedShape the shape used when the Chip is enabled, focused and selected
+     * @param focusedDisabledShape the shape used when the Chip is not enabled and focused
+     * @param pressedSelectedShape the shape used when the Chip is enabled, pressed and selected
+     * @param selectedDisabledShape the shape used when the Chip is not enabled and selected
+     * @param focusedSelectedDisabledShape the shape used when the Chip is not enabled, focused
+     * and selected
+     */
+    fun shape(
+        hasAvatar: Boolean,
+        shape: Shape = if (hasAvatar) ContainerShapeWithAvatar else ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        selectedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedSelectedShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape,
+        pressedSelectedShape: Shape = shape,
+        selectedDisabledShape: Shape = disabledShape,
+        focusedSelectedDisabledShape: Shape = disabledShape
+    ) = SelectableChipShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        selectedShape = selectedShape,
+        disabledShape = disabledShape,
+        focusedSelectedShape = focusedSelectedShape,
+        focusedDisabledShape = focusedDisabledShape,
+        pressedSelectedShape = pressedSelectedShape,
+        selectedDisabledShape = selectedDisabledShape,
+        focusedSelectedDisabledShape = focusedSelectedDisabledShape
+    )
+
+    /**
+     * Creates a [SelectableChipColors] that represents the default container and content colors
+     * used in an [InputChip]
+     *
+     * @param containerColor the container color used when the Chip is enabled, and has no
+     * other [Interaction]s
+     * @param contentColor the content color used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedContainerColor the container color used when the Chip is enabled and focused
+     * @param focusedContentColor the content color used when the Chip is enabled and focused
+     * @param pressedContainerColor the container color used when the Chip is enabled and pressed
+     * @param pressedContentColor the content color used when the Chip is enabled and pressed
+     * @param selectedContainerColor the container color used when the Chip is enabled and selected
+     * @param selectedContentColor the content color used when the Chip is enabled and selected
+     * @param disabledContainerColor the container color used when the Chip is not enabled
+     * @param disabledContentColor the content color used when the Chip is not enabled
+     * @param focusedSelectedContainerColor the container color used when the Chip is enabled,
+     * focused and selected
+     * @param focusedSelectedContentColor the content color used when the Chip is enabled,
+     * focused and selected
+     * @param pressedSelectedContainerColor the container color used when the Chip is enabled,
+     * pressed and selected
+     * @param pressedSelectedContentColor the content color used when the Chip is enabled, pressed
+     * and selected
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        pressedContentColor: Color = MaterialTheme.colorScheme.surface,
+        selectedContainerColor: Color = MaterialTheme.colorScheme.secondaryContainer.copy(
+            alpha = SelectedBackgroundColorOpacity
+        ),
+        selectedContentColor: Color = MaterialTheme.colorScheme.onSecondaryContainer,
+        disabledContainerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(
+            alpha = DisabledBackgroundColorOpacity
+        ),
+        disabledContentColor: Color = MaterialTheme.colorScheme.border.copy(
+            alpha = DisabledContentColorOpacity
+        ),
+        focusedSelectedContainerColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
+        focusedSelectedContentColor: Color = MaterialTheme.colorScheme.onPrimary,
+        pressedSelectedContainerColor: Color = MaterialTheme.colorScheme.secondary,
+        pressedSelectedContentColor: Color = MaterialTheme.colorScheme.onSecondary,
+    ) = SelectableChipColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        selectedContainerColor = selectedContainerColor,
+        selectedContentColor = selectedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+        focusedSelectedContainerColor = focusedSelectedContainerColor,
+        focusedSelectedContentColor = focusedSelectedContentColor,
+        pressedSelectedContainerColor = pressedSelectedContainerColor,
+        pressedSelectedContentColor = pressedSelectedContentColor,
+    )
+
+    /**
+     * Creates a [SelectableChipScale] that represents the default scaleFactors used in an
+     * [InputChip]. scaleFactors are used to modify the size of a composable in different
+     * [Interaction] states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc
+     *
+     * @param scale the scaleFactor used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedScale the scaleFactor used when the Chip is enabled and focused
+     * @param pressedScale the scaleFactor used when the Chip is enabled and pressed
+     * @param selectedScale the scaleFactor used when the Chip is enabled and selected
+     * @param disabledScale the scaleFactor used when the Chip is not enabled
+     * @param focusedSelectedScale the scaleFactor used when the Chip is enabled, focused and
+     * selected
+     * @param focusedDisabledScale the scaleFactor used when the Chip is not enabled and
+     * focused
+     * @param pressedSelectedScale the scaleFactor used when the Chip is enabled, pressed and
+     * selected
+     * @param selectedDisabledScale the scaleFactor used when the Chip is not enabled and
+     * selected
+     * @param focusedSelectedDisabledScale the scaleFactor used when the Chip is not enabled,
+     * focused and selected
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) selectedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedSelectedScale: Float = focusedScale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale,
+        @FloatRange(from = 0.0) pressedSelectedScale: Float = scale,
+        @FloatRange(from = 0.0) selectedDisabledScale: Float = disabledScale,
+        @FloatRange(from = 0.0) focusedSelectedDisabledScale: Float = disabledScale
+    ) = SelectableChipScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        selectedScale = selectedScale,
+        disabledScale = disabledScale,
+        focusedSelectedScale = focusedSelectedScale,
+        focusedDisabledScale = focusedDisabledScale,
+        pressedSelectedScale = pressedSelectedScale,
+        selectedDisabledScale = selectedDisabledScale,
+        focusedSelectedDisabledScale = focusedSelectedDisabledScale
+    )
+
+    /**
+     * Creates a [SelectableChipBorder] that represents the default [Border]s applied on an
+     * [InputChip] in different [Interaction] states
+     *
+     * @param hasAvatar changes the default border shape based on whether the avatar composable is
+     * not null in the Chip
+     * @param border the [Border] used when the Chip is enabled, and has no other
+     * [Interaction]s
+     * @param focusedBorder the [Border] used when the Chip is enabled and focused
+     * @param pressedBorder the [Border] used when the Chip is enabled and pressed
+     * @param selectedBorder the [Border] used when the Chip is enabled and selected
+     * @param disabledBorder the [Border] used when the Chip is not enabled
+     * @param focusedSelectedBorder the [Border] used when the Chip is enabled, focused and
+     * selected
+     * @param focusedDisabledBorder the [Border] used when the Chip is not enabled and focused
+     * @param pressedSelectedBorder the [Border] used when the Chip is enabled, pressed and
+     * selected
+     * @param selectedDisabledBorder the [Border] used when the Chip is not enabled and
+     * selected
+     * @param focusedSelectedDisabledBorder the [Border] used when the Chip is not enabled,
+     * focused and selected
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        hasAvatar: Boolean,
+        border: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.border
+            ),
+            shape = if (hasAvatar) ContainerShapeWithAvatar else ContainerShape
+        ),
+        focusedBorder: Border = Border.None,
+        pressedBorder: Border = focusedBorder,
+        selectedBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.secondary
+            ),
+            shape = if (hasAvatar) ContainerShapeWithAvatar else ContainerShape
+        ),
+        disabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.surfaceVariant
+            ),
+            shape = if (hasAvatar) ContainerShapeWithAvatar else ContainerShape
+        ),
+        focusedSelectedBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.1.dp,
+                color = MaterialTheme.colorScheme.onPrimaryContainer
+            ),
+            shape = if (hasAvatar) ContainerShapeWithAvatar else ContainerShape
+        ),
+        focusedDisabledBorder: Border = border,
+        pressedSelectedBorder: Border = Border.None,
+        selectedDisabledBorder: Border = Border.None,
+        focusedSelectedDisabledBorder: Border = border
+    ) = SelectableChipBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        selectedBorder = selectedBorder,
+        disabledBorder = disabledBorder,
+        focusedSelectedBorder = focusedSelectedBorder,
+        focusedDisabledBorder = focusedDisabledBorder,
+        pressedSelectedBorder = pressedSelectedBorder,
+        selectedDisabledBorder = selectedDisabledBorder,
+        focusedSelectedDisabledBorder = focusedSelectedDisabledBorder,
+    )
+
+    /**
+     * Creates a [SelectableChipGlow] that represents the default [Glow]s used in an [InputChip]
+     *
+     * @param glow the [Glow] used when the Chip is enabled, and has no other [Interaction]s
+     * @param focusedGlow the [Glow] used when the Chip is enabled and focused
+     * @param pressedGlow the [Glow] used when the Chip is enabled and pressed
+     * @param selectedGlow the [Glow] used when the Chip is enabled and selected
+     * @param focusedSelectedGlow the [Glow] used when the Chip is enabled, focused and selected
+     * @param pressedSelectedGlow the [Glow] used when the Chip is enabled, pressed and selected
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow,
+        selectedGlow: Glow = glow,
+        focusedSelectedGlow: Glow = focusedGlow,
+        pressedSelectedGlow: Glow = glow
+    ) = SelectableChipGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow,
+        selectedGlow = selectedGlow,
+        focusedSelectedGlow = focusedSelectedGlow,
+        pressedSelectedGlow = pressedSelectedGlow
+    )
+}
+
+/**
+ * Contains the default values used by [SuggestionChip].
+ */
+@ExperimentalTvMaterial3Api
+object SuggestionChipDefaults {
+    /**
+     * The height applied to a suggestion chip.
+     * Note that you can override it by applying Modifier.height directly on a chip.
+     */
+    val ContainerHeight = 36.dp
+
+    /**
+     * The default [Shape] applied to a suggestion chip
+     */
+    val ContainerShape = RoundedCornerShape(8.dp)
+
+    private const val DisabledBackgroundColorOpacity = 0.2f
+    private const val DisabledContentColorOpacity = 0.8f
+
+    /**
+     * Creates a [ClickableChipShape] that represents the default container shapes used in a
+     * [SuggestionChip]
+     *
+     * @param shape the shape used when the Chip is enabled, and has no other [Interaction]s
+     * @param focusedShape the shape used when the Chip is enabled and focused
+     * @param pressedShape the shape used when the Chip is enabled pressed
+     * @param disabledShape the shape used when the Chip is not enabled
+     * @param focusedDisabledShape the shape used when the Chip is not enabled and focused
+     */
+    fun shape(
+        shape: Shape = ContainerShape,
+        focusedShape: Shape = shape,
+        pressedShape: Shape = shape,
+        disabledShape: Shape = shape,
+        focusedDisabledShape: Shape = disabledShape
+    ) = ClickableChipShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+
+    /**
+     * Creates a [ClickableChipColors] that represents the default container and content colors
+     * used in a [SuggestionChip]
+     *
+     * @param containerColor the container color of this Chip when enabled
+     * @param contentColor the content color of this Chip when enabled
+     * @param focusedContainerColor the container color of this Chip when enabled and focused
+     * @param focusedContentColor the content color of this Chip when enabled and focused
+     * @param pressedContainerColor the container color of this Chip when enabled and pressed
+     * @param pressedContentColor the content color of this Chip when enabled and pressed
+     * @param disabledContainerColor the container color of this Chip when not enabled
+     * @param disabledContentColor the content color of this Chip when not enabled
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun colors(
+        containerColor: Color = Color.Transparent,
+        contentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        focusedContainerColor: Color = MaterialTheme.colorScheme.onSurface,
+        focusedContentColor: Color = MaterialTheme.colorScheme.inverseOnSurface,
+        pressedContainerColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+        pressedContentColor: Color = MaterialTheme.colorScheme.surface,
+        disabledContainerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(
+            alpha = DisabledBackgroundColorOpacity
+        ),
+        disabledContentColor: Color = MaterialTheme.colorScheme.border.copy(
+            alpha = DisabledContentColorOpacity
+        )
+    ) = ClickableChipColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+    )
+
+    /**
+     * Creates a [ClickableChipScale] that represents the default scaleFactors used in a
+     * [SuggestionChip].
+     * scaleFactors are used to modify the size of a composable in different [Interaction]
+     * states e.g. 1f (original) in default state, 1.2f (scaled up) in focused state,
+     * 0.8f (scaled down) in pressed state, etc
+     *
+     * @param scale the scaleFactor to be used for this Chip when enabled
+     * @param focusedScale the scaleFactor to be used for this Chip when focused
+     * @param pressedScale the scaleFactor to be used for this Chip when pressed
+     * @param disabledScale the scaleFactor to be used for this Chip when disabled
+     * @param focusedDisabledScale the scaleFactor to be used for this Chip when disabled and
+     * focused
+     */
+    fun scale(
+        @FloatRange(from = 0.0) scale: Float = 1f,
+        @FloatRange(from = 0.0) focusedScale: Float = 1.1f,
+        @FloatRange(from = 0.0) pressedScale: Float = scale,
+        @FloatRange(from = 0.0) disabledScale: Float = scale,
+        @FloatRange(from = 0.0) focusedDisabledScale: Float = disabledScale
+    ) = ClickableChipScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+
+    /**
+     * Creates a [ClickableChipBorder] that represents the default [Border]s applied on a
+     * [SuggestionChip] in different [Interaction] states
+     *
+     * @param border the [Border] to be used for this Chip when enabled
+     * @param focusedBorder the [Border] to be used for this Chip when focused
+     * @param pressedBorder the [Border] to be used for this Chip when pressed
+     * @param disabledBorder the [Border] to be used for this Chip when disabled
+     * @param focusedDisabledBorder the [Border] to be used for this Chip when disabled and
+     * focused
+     */
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        border: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.border
+            ),
+            shape = ContainerShape
+        ),
+        focusedBorder: Border = Border.None,
+        pressedBorder: Border = focusedBorder,
+        disabledBorder: Border = Border(
+            border = BorderStroke(
+                width = 1.dp,
+                color = MaterialTheme.colorScheme.surfaceVariant
+            ),
+            shape = ContainerShape
+        ),
+        focusedDisabledBorder: Border = border
+    ) = ClickableChipBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+
+    /**
+     * Creates a [ClickableChipGlow] that represents the default [Glow]s used in a [SuggestionChip]
+     *
+     * @param glow the Glow behind this Button when enabled
+     * @param focusedGlow the Glow behind this Button when focused
+     * @param pressedGlow the Glow behind this Button when pressed
+     */
+    fun glow(
+        glow: Glow = Glow.None,
+        focusedGlow: Glow = glow,
+        pressedGlow: Glow = glow
+    ) = ClickableChipGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
+
+/**
+ * The padding between the elements in the chip
+ */
+internal val HorizontalElementsPadding = 8.dp
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ChipStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ChipStyles.kt
new file mode 100644
index 0000000..78b04f2
--- /dev/null
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ChipStyles.kt
@@ -0,0 +1,701 @@
+/*
+ * 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.tv.material3
+
+import androidx.annotation.FloatRange
+import androidx.compose.foundation.Indication
+import androidx.compose.runtime.Immutable
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+
+/**
+ * Defines [Shape] for all TV [Indication] states of [ClickableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class ClickableChipShape internal constructor(
+    internal val shape: Shape,
+    internal val focusedShape: Shape,
+    internal val pressedShape: Shape,
+    internal val disabledShape: Shape,
+    internal val focusedDisabledShape: Shape
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as ClickableChipShape
+
+        if (shape != other.shape) return false
+        if (focusedShape != other.focusedShape) return false
+        if (pressedShape != other.pressedShape) return false
+        if (disabledShape != other.disabledShape) return false
+        if (focusedDisabledShape != other.focusedDisabledShape) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = shape.hashCode()
+        result = 31 * result + focusedShape.hashCode()
+        result = 31 * result + pressedShape.hashCode()
+        result = 31 * result + disabledShape.hashCode()
+        result = 31 * result + focusedDisabledShape.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "ClickableChipShape(shape=$shape, focusedShape=$focusedShape, " +
+            "pressedShape=$pressedShape, disabledShape=$disabledShape, " +
+            "focusedDisabledShape=$focusedDisabledShape)"
+    }
+
+    internal fun toClickableSurfaceShape() = ClickableSurfaceShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        disabledShape = disabledShape,
+        focusedDisabledShape = focusedDisabledShape
+    )
+}
+
+/**
+ * Defines [Shape] for all TV [Indication] states of [SelectableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class SelectableChipShape internal constructor(
+    internal val shape: Shape,
+    internal val focusedShape: Shape,
+    internal val pressedShape: Shape,
+    internal val selectedShape: Shape,
+    internal val disabledShape: Shape,
+    internal val focusedSelectedShape: Shape,
+    internal val focusedDisabledShape: Shape,
+    internal val pressedSelectedShape: Shape,
+    internal val selectedDisabledShape: Shape,
+    internal val focusedSelectedDisabledShape: Shape
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as SelectableChipShape
+
+        if (shape != other.shape) return false
+        if (focusedShape != other.focusedShape) return false
+        if (pressedShape != other.pressedShape) return false
+        if (selectedShape != other.selectedShape) return false
+        if (disabledShape != other.disabledShape) return false
+        if (focusedSelectedShape != other.focusedSelectedShape) return false
+        if (focusedDisabledShape != other.focusedDisabledShape) return false
+        if (pressedSelectedShape != other.pressedSelectedShape) return false
+        if (selectedDisabledShape != other.selectedDisabledShape) return false
+        if (focusedSelectedDisabledShape != other.focusedSelectedDisabledShape) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = shape.hashCode()
+        result = 31 * result + focusedShape.hashCode()
+        result = 31 * result + pressedShape.hashCode()
+        result = 31 * result + selectedShape.hashCode()
+        result = 31 * result + disabledShape.hashCode()
+        result = 31 * result + focusedSelectedShape.hashCode()
+        result = 31 * result + focusedDisabledShape.hashCode()
+        result = 31 * result + pressedSelectedShape.hashCode()
+        result = 31 * result + selectedDisabledShape.hashCode()
+        result = 31 * result + focusedSelectedDisabledShape.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "SelectableChipShape(shape=$shape, focusedShape=$focusedShape, " +
+            "pressedShape=$pressedShape, selectedShape=$selectedShape, " +
+            "disabledShape=$disabledShape, focusedSelectedShape=$focusedSelectedShape, " +
+            "focusedDisabledShape=$focusedDisabledShape," +
+            "pressedSelectedShape=$pressedSelectedShape, " +
+            "selectedDisabledShape=$selectedDisabledShape, " +
+            "focusedSelectedDisabledShape=$focusedSelectedDisabledShape)"
+    }
+
+    internal fun toToggleableSurfaceShape() = ToggleableSurfaceShape(
+        shape = shape,
+        focusedShape = focusedShape,
+        pressedShape = pressedShape,
+        selectedShape = selectedShape,
+        disabledShape = disabledShape,
+        focusedSelectedShape = focusedSelectedShape,
+        focusedDisabledShape = focusedDisabledShape,
+        pressedSelectedShape = pressedSelectedShape,
+        selectedDisabledShape = selectedDisabledShape,
+        focusedSelectedDisabledShape = focusedSelectedDisabledShape
+    )
+}
+
+/**
+ * Defines [Color] for all TV [Indication] states of [ClickableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class ClickableChipColors internal constructor(
+    internal val containerColor: Color,
+    internal val contentColor: Color,
+    internal val focusedContainerColor: Color,
+    internal val focusedContentColor: Color,
+    internal val pressedContainerColor: Color,
+    internal val pressedContentColor: Color,
+    internal val disabledContainerColor: Color,
+    internal val disabledContentColor: Color
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as ClickableChipColors
+
+        if (containerColor != other.containerColor) return false
+        if (contentColor != other.contentColor) return false
+        if (focusedContainerColor != other.focusedContainerColor) return false
+        if (focusedContentColor != other.focusedContentColor) return false
+        if (pressedContainerColor != other.pressedContainerColor) return false
+        if (pressedContentColor != other.pressedContentColor) return false
+        if (disabledContainerColor != other.disabledContainerColor) return false
+        if (disabledContentColor != other.disabledContentColor) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = containerColor.hashCode()
+        result = 31 * result + contentColor.hashCode()
+        result = 31 * result + focusedContainerColor.hashCode()
+        result = 31 * result + focusedContentColor.hashCode()
+        result = 31 * result + pressedContainerColor.hashCode()
+        result = 31 * result + pressedContentColor.hashCode()
+        result = 31 * result + disabledContainerColor.hashCode()
+        result = 31 * result + disabledContentColor.hashCode()
+        return result
+    }
+
+    internal fun toClickableSurfaceColors() = ClickableSurfaceColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+    )
+
+    override fun toString(): String {
+        return "ClickableChipColors(containerColor=$containerColor, contentColor=$contentColor, " +
+            "focusedContainerColor=$focusedContainerColor, focusedContentColor=" +
+            "$focusedContentColor, pressedContainerColor=$pressedContainerColor, " +
+            "pressedContentColor=$pressedContentColor, disabledContainerColor=" +
+            "$disabledContainerColor, disabledContentColor=$disabledContentColor)"
+    }
+}
+
+/**
+ * Defines [Color] for all TV [Indication] states of [SelectableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class SelectableChipColors internal constructor(
+    internal val containerColor: Color,
+    internal val contentColor: Color,
+    internal val focusedContainerColor: Color,
+    internal val focusedContentColor: Color,
+    internal val pressedContainerColor: Color,
+    internal val pressedContentColor: Color,
+    internal val selectedContainerColor: Color,
+    internal val selectedContentColor: Color,
+    internal val disabledContainerColor: Color,
+    internal val disabledContentColor: Color,
+    internal val focusedSelectedContainerColor: Color,
+    internal val focusedSelectedContentColor: Color,
+    internal val pressedSelectedContainerColor: Color,
+    internal val pressedSelectedContentColor: Color
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as SelectableChipColors
+
+        if (containerColor != other.containerColor) return false
+        if (contentColor != other.contentColor) return false
+        if (focusedContainerColor != other.focusedContainerColor) return false
+        if (focusedContentColor != other.focusedContentColor) return false
+        if (pressedContainerColor != other.pressedContainerColor) return false
+        if (pressedContentColor != other.pressedContentColor) return false
+        if (selectedContainerColor != other.selectedContainerColor) return false
+        if (selectedContentColor != other.selectedContentColor) return false
+        if (disabledContainerColor != other.disabledContainerColor) return false
+        if (disabledContentColor != other.disabledContentColor) return false
+        if (focusedSelectedContainerColor != other.focusedSelectedContainerColor) return false
+        if (focusedSelectedContentColor != other.focusedSelectedContentColor) return false
+        if (pressedSelectedContainerColor != other.pressedSelectedContainerColor) return false
+        if (pressedSelectedContentColor != other.pressedSelectedContentColor) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = containerColor.hashCode()
+        result = 31 * result + contentColor.hashCode()
+        result = 31 * result + focusedContainerColor.hashCode()
+        result = 31 * result + focusedContentColor.hashCode()
+        result = 31 * result + pressedContainerColor.hashCode()
+        result = 31 * result + pressedContentColor.hashCode()
+        result = 31 * result + selectedContainerColor.hashCode()
+        result = 31 * result + selectedContentColor.hashCode()
+        result = 31 * result + disabledContainerColor.hashCode()
+        result = 31 * result + disabledContentColor.hashCode()
+        result = 31 * result + focusedSelectedContainerColor.hashCode()
+        result = 31 * result + focusedSelectedContentColor.hashCode()
+        result = 31 * result + pressedSelectedContainerColor.hashCode()
+        result = 31 * result + pressedSelectedContentColor.hashCode()
+        return result
+    }
+
+    internal fun toToggleableSurfaceColors() = ToggleableSurfaceColors(
+        containerColor = containerColor,
+        contentColor = contentColor,
+        focusedContainerColor = focusedContainerColor,
+        focusedContentColor = focusedContentColor,
+        pressedContainerColor = pressedContainerColor,
+        pressedContentColor = pressedContentColor,
+        selectedContainerColor = selectedContainerColor,
+        selectedContentColor = selectedContentColor,
+        disabledContainerColor = disabledContainerColor,
+        disabledContentColor = disabledContentColor,
+        focusedSelectedContainerColor = focusedSelectedContainerColor,
+        focusedSelectedContentColor = focusedSelectedContentColor,
+        pressedSelectedContainerColor = pressedSelectedContainerColor,
+        pressedSelectedContentColor = pressedSelectedContentColor,
+    )
+
+    override fun toString(): String {
+        return "SelectableChipColors(containerColor=$containerColor, " +
+            "contentColor=$contentColor, focusedContainerColor=$focusedContainerColor, " +
+            "focusedContentColor=$focusedContentColor, " +
+            "pressedContainerColor=$pressedContainerColor, " +
+            "pressedContentColor=$pressedContentColor, " +
+            "selectedContainerColor=$selectedContainerColor, " +
+            "selectedContentColor=$selectedContentColor, " +
+            "disabledContainerColor=$disabledContainerColor, " +
+            "disabledContentColor=$disabledContentColor, " +
+            "focusedSelectedContainerColor=$focusedSelectedContainerColor, " +
+            "focusedSelectedContentColor=$focusedSelectedContentColor, " +
+            "pressedSelectedContainerColor=$pressedSelectedContainerColor, " +
+            "pressedSelectedContentColor=$pressedSelectedContentColor)"
+    }
+}
+
+/**
+ * Defines the scale for all TV states of [ClickableChip]. Note: This scale must always be a
+ * non-negative float.
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class ClickableChipScale internal constructor(
+    @FloatRange(from = 0.0) internal val scale: Float,
+    @FloatRange(from = 0.0) internal val focusedScale: Float,
+    @FloatRange(from = 0.0) internal val pressedScale: Float,
+    @FloatRange(from = 0.0) internal val disabledScale: Float,
+    @FloatRange(from = 0.0) internal val focusedDisabledScale: Float
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as ClickableChipScale
+
+        if (scale != other.scale) return false
+        if (focusedScale != other.focusedScale) return false
+        if (pressedScale != other.pressedScale) return false
+        if (disabledScale != other.disabledScale) return false
+        if (focusedDisabledScale != other.focusedDisabledScale) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = scale.hashCode()
+        result = 31 * result + focusedScale.hashCode()
+        result = 31 * result + pressedScale.hashCode()
+        result = 31 * result + disabledScale.hashCode()
+        result = 31 * result + focusedDisabledScale.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "ClickableChipScale(scale=$scale, focusedScale=$focusedScale, " +
+            "pressedScale=$pressedScale, disabledScale=$disabledScale, " +
+            "focusedDisabledScale=$focusedDisabledScale)"
+    }
+
+    companion object {
+        /**
+         * Signifies the absence of a [ScaleIndication] in ClickableChip component.
+         */
+        val None = ClickableChipScale(
+            scale = 1f,
+            focusedScale = 1f,
+            pressedScale = 1f,
+            disabledScale = 1f,
+            focusedDisabledScale = 1f,
+        )
+    }
+
+    internal fun toClickableSurfaceScale() = ClickableSurfaceScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        disabledScale = disabledScale,
+        focusedDisabledScale = focusedDisabledScale
+    )
+}
+
+/**
+ * Defines the scale for all TV states of [SelectableChip]. Note: This scale must always be a
+ * non-negative float.
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class SelectableChipScale internal constructor(
+    @FloatRange(from = 0.0) internal val scale: Float,
+    @FloatRange(from = 0.0) internal val focusedScale: Float,
+    @FloatRange(from = 0.0) internal val pressedScale: Float,
+    @FloatRange(from = 0.0) internal val selectedScale: Float,
+    @FloatRange(from = 0.0) internal val disabledScale: Float,
+    @FloatRange(from = 0.0) internal val focusedSelectedScale: Float,
+    @FloatRange(from = 0.0) internal val focusedDisabledScale: Float,
+    @FloatRange(from = 0.0) internal val pressedSelectedScale: Float,
+    @FloatRange(from = 0.0) internal val selectedDisabledScale: Float,
+    @FloatRange(from = 0.0) internal val focusedSelectedDisabledScale: Float
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as SelectableChipScale
+
+        if (scale != other.scale) return false
+        if (focusedScale != other.focusedScale) return false
+        if (pressedScale != other.pressedScale) return false
+        if (selectedScale != other.selectedScale) return false
+        if (disabledScale != other.disabledScale) return false
+        if (focusedSelectedScale != other.focusedSelectedScale) return false
+        if (focusedDisabledScale != other.focusedDisabledScale) return false
+        if (pressedSelectedScale != other.pressedSelectedScale) return false
+        if (selectedDisabledScale != other.selectedDisabledScale) return false
+        if (focusedSelectedDisabledScale != other.focusedSelectedDisabledScale) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = scale.hashCode()
+        result = 31 * result + focusedScale.hashCode()
+        result = 31 * result + pressedScale.hashCode()
+        result = 31 * result + selectedScale.hashCode()
+        result = 31 * result + disabledScale.hashCode()
+        result = 31 * result + focusedSelectedScale.hashCode()
+        result = 31 * result + focusedDisabledScale.hashCode()
+        result = 31 * result + pressedSelectedScale.hashCode()
+        result = 31 * result + selectedDisabledScale.hashCode()
+        result = 31 * result + focusedSelectedDisabledScale.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "SelectableChipScale(scale=$scale, focusedScale=$focusedScale, " +
+            "pressedScale=$pressedScale, selectedScale=$selectedScale, " +
+            "disabledScale=$disabledScale, focusedSelectedScale=$focusedSelectedScale, " +
+            "focusedDisabledScale=$focusedDisabledScale, " +
+            "pressedSelectedScale=$pressedSelectedScale, " +
+            "selectedDisabledScale=$selectedDisabledScale, " +
+            "focusedSelectedDisabledScale=$focusedSelectedDisabledScale)"
+    }
+
+    companion object {
+        /**
+         * Signifies the absence of a [ScaleIndication] in SelectableChip component.
+         */
+        val None = SelectableChipScale(
+            scale = 1f,
+            focusedScale = 1f,
+            pressedScale = 1f,
+            selectedScale = 1f,
+            disabledScale = 1f,
+            focusedSelectedScale = 1f,
+            focusedDisabledScale = 1f,
+            pressedSelectedScale = 1f,
+            selectedDisabledScale = 1f,
+            focusedSelectedDisabledScale = 1f,
+        )
+    }
+
+    internal fun toToggleableSurfaceScale() = ToggleableSurfaceScale(
+        scale = scale,
+        focusedScale = focusedScale,
+        pressedScale = pressedScale,
+        selectedScale = selectedScale,
+        disabledScale = disabledScale,
+        focusedSelectedScale = focusedSelectedScale,
+        focusedDisabledScale = focusedDisabledScale,
+        pressedSelectedScale = pressedSelectedScale,
+        selectedDisabledScale = selectedDisabledScale,
+        focusedSelectedDisabledScale = focusedSelectedDisabledScale
+    )
+}
+
+/**
+ * Defines [Border] for all TV [Indication] states of [ClickableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class ClickableChipBorder internal constructor(
+    internal val border: Border,
+    internal val focusedBorder: Border,
+    internal val pressedBorder: Border,
+    internal val disabledBorder: Border,
+    internal val focusedDisabledBorder: Border
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as ClickableChipBorder
+
+        if (border != other.border) return false
+        if (focusedBorder != other.focusedBorder) return false
+        if (pressedBorder != other.pressedBorder) return false
+        if (disabledBorder != other.disabledBorder) return false
+        if (focusedDisabledBorder != other.focusedDisabledBorder) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = border.hashCode()
+        result = 31 * result + focusedBorder.hashCode()
+        result = 31 * result + pressedBorder.hashCode()
+        result = 31 * result + disabledBorder.hashCode()
+        result = 31 * result + focusedDisabledBorder.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "ClickableChipBorder(border=$border, focusedBorder=$focusedBorder, " +
+            "pressedBorder=$pressedBorder, disabledBorder=$disabledBorder, " +
+            "focusedDisabledBorder=$focusedDisabledBorder)"
+    }
+
+    internal fun toClickableSurfaceBorder() = ClickableSurfaceBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        disabledBorder = disabledBorder,
+        focusedDisabledBorder = focusedDisabledBorder
+    )
+}
+
+/**
+ * Defines [Border] for all TV [Indication] states of [SelectableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class SelectableChipBorder internal constructor(
+    internal val border: Border,
+    internal val focusedBorder: Border,
+    internal val pressedBorder: Border,
+    internal val selectedBorder: Border,
+    internal val disabledBorder: Border,
+    internal val focusedSelectedBorder: Border,
+    internal val focusedDisabledBorder: Border,
+    internal val pressedSelectedBorder: Border,
+    internal val selectedDisabledBorder: Border,
+    internal val focusedSelectedDisabledBorder: Border
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as SelectableChipBorder
+
+        if (border != other.border) return false
+        if (focusedBorder != other.focusedBorder) return false
+        if (pressedBorder != other.pressedBorder) return false
+        if (selectedBorder != other.selectedBorder) return false
+        if (disabledBorder != other.disabledBorder) return false
+        if (focusedSelectedBorder != other.focusedSelectedBorder) return false
+        if (focusedDisabledBorder != other.focusedDisabledBorder) return false
+        if (pressedSelectedBorder != other.pressedSelectedBorder) return false
+        if (selectedDisabledBorder != other.selectedDisabledBorder) return false
+        if (focusedSelectedDisabledBorder != other.focusedSelectedDisabledBorder) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = border.hashCode()
+        result = 31 * result + focusedBorder.hashCode()
+        result = 31 * result + pressedBorder.hashCode()
+        result = 31 * result + selectedBorder.hashCode()
+        result = 31 * result + disabledBorder.hashCode()
+        result = 31 * result + focusedSelectedBorder.hashCode()
+        result = 31 * result + focusedDisabledBorder.hashCode()
+        result = 31 * result + pressedSelectedBorder.hashCode()
+        result = 31 * result + selectedDisabledBorder.hashCode()
+        result = 31 * result + focusedSelectedDisabledBorder.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "SelectableChipBorder(border=$border, focusedBorder=$focusedBorder, " +
+            "pressedBorder=$pressedBorder, selectedBorder=$selectedBorder, " +
+            "disabledBorder=$disabledBorder, focusedSelectedBorder=$focusedSelectedBorder, " +
+            "focusedDisabledBorder=$focusedDisabledBorder, " +
+            "pressedSelectedBorder=$pressedSelectedBorder, " +
+            "selectedDisabledBorder=$selectedDisabledBorder, " +
+            "focusedSelectedDisabledBorder=$focusedSelectedDisabledBorder)"
+    }
+
+    internal fun toToggleableSurfaceBorder() = ToggleableSurfaceBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder,
+        selectedBorder = selectedBorder,
+        disabledBorder = disabledBorder,
+        focusedSelectedBorder = focusedSelectedBorder,
+        focusedDisabledBorder = focusedDisabledBorder,
+        pressedSelectedBorder = pressedSelectedBorder,
+        selectedDisabledBorder = selectedDisabledBorder,
+        focusedSelectedDisabledBorder = focusedSelectedDisabledBorder
+    )
+}
+
+/**
+ * Defines [Glow] for all TV [Indication] states of [ClickableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class ClickableChipGlow internal constructor(
+    internal val glow: Glow,
+    internal val focusedGlow: Glow,
+    internal val pressedGlow: Glow
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as ClickableChipGlow
+
+        if (glow != other.glow) return false
+        if (focusedGlow != other.focusedGlow) return false
+        if (pressedGlow != other.pressedGlow) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = glow.hashCode()
+        result = 31 * result + focusedGlow.hashCode()
+        result = 31 * result + pressedGlow.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "ClickableChipGlow(glow=$glow, focusedGlow=$focusedGlow, pressedGlow=$pressedGlow)"
+    }
+
+    internal fun toClickableSurfaceGlow() = ClickableSurfaceGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow
+    )
+}
+
+/**
+ * Defines [Glow] for all TV [Indication] states of [SelectableChip].
+ */
+@ExperimentalTvMaterial3Api
+@Immutable
+class SelectableChipGlow internal constructor(
+    internal val glow: Glow,
+    internal val focusedGlow: Glow,
+    internal val pressedGlow: Glow,
+    internal val selectedGlow: Glow,
+    internal val focusedSelectedGlow: Glow,
+    internal val pressedSelectedGlow: Glow
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null || this::class != other::class) return false
+
+        other as SelectableChipGlow
+
+        if (glow != other.glow) return false
+        if (focusedGlow != other.focusedGlow) return false
+        if (pressedGlow != other.pressedGlow) return false
+        if (selectedGlow != other.selectedGlow) return false
+        if (focusedSelectedGlow != other.focusedSelectedGlow) return false
+        if (pressedSelectedGlow != other.pressedSelectedGlow) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = glow.hashCode()
+        result = 31 * result + focusedGlow.hashCode()
+        result = 31 * result + pressedGlow.hashCode()
+        result = 31 * result + selectedGlow.hashCode()
+        result = 31 * result + focusedSelectedGlow.hashCode()
+        result = 31 * result + pressedSelectedGlow.hashCode()
+
+        return result
+    }
+
+    override fun toString(): String {
+        return "SelectableChipGlow(glow=$glow, focusedGlow=$focusedGlow, " +
+            "pressedGlow=$pressedGlow, selectedGlow=$selectedGlow, " +
+            "focusedSelectedGlow=$focusedSelectedGlow, " +
+            "pressedSelectedGlow=$pressedSelectedGlow)"
+    }
+
+    internal fun toToggleableSurfaceGlow() = ToggleableSurfaceGlow(
+        glow = glow,
+        focusedGlow = focusedGlow,
+        pressedGlow = pressedGlow,
+        selectedGlow = selectedGlow,
+        focusedSelectedGlow = focusedSelectedGlow,
+        pressedSelectedGlow = pressedSelectedGlow
+    )
+}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedLayout.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedLayout.kt
index 882ac9d..bddca99 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedLayout.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedLayout.kt
@@ -124,7 +124,9 @@
             curvedRowChild.SubComposition()
         }
     ) { measurables, constraints ->
-        require(constraints.hasBoundedHeight || constraints.hasBoundedWidth)
+        require(constraints.hasBoundedHeight || constraints.hasBoundedWidth) {
+            "either height or width should be bounded"
+        }
         // We take as much room as possible, the same in both dimensions, within the constraints
         val diameter = min(
             if (constraints.hasBoundedWidth) constraints.maxWidth else Int.MAX_VALUE,
@@ -138,7 +140,7 @@
             with(curvedRowChild) {
                 val iterator = measurables.iterator()
                 initializeMeasure(iterator)
-                require(!iterator.hasNext())
+                require(!iterator.hasNext()) { "unused measurable" }
             }
         }
 
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
index 14ceb4a5..ea184bf 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
@@ -737,7 +737,7 @@
 public fun Modifier.verticalNegativePadding(
     extraPadding: Dp,
 ) = layout { measurable, constraints ->
-    require(constraints.hasBoundedHeight)
+    require(constraints.hasBoundedHeight) { "height should be bounded" }
     val topAndBottomPadding = (extraPadding * 2).roundToPx()
     val placeable = measurable.measure(
         constraints.copy(
diff --git a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SliderTest.kt b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SliderTest.kt
new file mode 100644
index 0000000..7303af4
--- /dev/null
+++ b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SliderTest.kt
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.materialcore
+
+import android.os.Build
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.testutils.assertDoesNotContainColor
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.assertContentDescriptionContains
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChild
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.SdkSuppress
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+public class SliderTest {
+    @get:Rule
+    public val rule = createComposeRule()
+
+    @Test
+    public fun slider_button_supports_testtag() {
+        rule.setContent {
+            SliderButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @Test
+    public fun slider_button_has_click_action_when_enabled() {
+        rule.setContent {
+            SliderButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+    }
+
+    @Test
+    public fun slider_button_has_click_action_when_disabled() {
+        rule.setContent {
+            SliderButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+    }
+
+    @Test
+    public fun slider_button_is_correctly_enabled() {
+        rule.setContent {
+            SliderButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+    }
+
+    @Test
+    public fun slider_button_is_correctly_disabled() {
+        rule.setContent {
+            SliderButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsNotEnabled()
+    }
+
+    @Test
+    public fun slider_button_responds_to_click_when_enabled() {
+        var clicked = false
+        rule.setContent {
+            SliderButtonWithDefaults(
+                onClick = { clicked = true },
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            Assert.assertEquals(true, clicked)
+        }
+    }
+
+    @Test
+    public fun slider_button_does_not_respond_to_click_when_disabled() {
+        var clicked = false
+        rule.setContent {
+            SliderButtonWithDefaults(
+                onClick = { clicked = true },
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            Assert.assertEquals(false, clicked)
+        }
+    }
+
+    @Test
+    public fun sets_icon_content_description_for_slider_button() {
+        val testContentDescription = "testContentDescription"
+
+        rule.setContent {
+            SliderButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                content = { TestImage(iconLabel = testContentDescription) }
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG, true)
+            .onChild()
+            .assertContentDescriptionContains(testContentDescription)
+    }
+
+    @Test
+    public fun slider_progress_bar_supports_testtag() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public fun slider_progress_bar_draws_bar_separator_when_segments_greater_than_one() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                barSeparatorColor = mutableStateOf(BarSeparatorColor),
+                visibleSegments = 5
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertContainsColor(expectedColor = BarSeparatorColor, 0.1f)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public fun slider_progress_bar_does_not_draw_bar_separator_when_segments_equals_one() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                barSeparatorColor = mutableStateOf(BarSeparatorColor),
+                visibleSegments = 1
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertDoesNotContainColor(unexpectedColor = BarSeparatorColor)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public fun draws_selected_and_unselected_bar_when_ratio_between_zero_and_one() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                selectedBarColor = mutableStateOf(SelectedBarColor),
+                unselectedBarColor = mutableStateOf(UnselectedBarColor),
+                valueRatio = 0.4f
+            )
+        }
+
+        val progressBarImage = rule.onNodeWithTag(TEST_TAG).captureToImage()
+        progressBarImage.assertContainsColor(expectedColor = SelectedBarColor, 1f)
+        progressBarImage.assertContainsColor(expectedColor = UnselectedBarColor, 1f)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public fun draws_selected_bar_only_when_ratio_equals_one() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                selectedBarColor = mutableStateOf(SelectedBarColor),
+                unselectedBarColor = mutableStateOf(UnselectedBarColor),
+                valueRatio = 1f
+            )
+        }
+
+        val progressBarImage = rule.onNodeWithTag(TEST_TAG).captureToImage()
+        progressBarImage.assertContainsColor(expectedColor = SelectedBarColor, 1f)
+        progressBarImage.assertDoesNotContainColor(unexpectedColor = UnselectedBarColor)
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public fun draws_unselected_bar_only_when_ratio_equals_zero() {
+        rule.setContent {
+            ProgressBarWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+                selectedBarColor = mutableStateOf(SelectedBarColor),
+                unselectedBarColor = mutableStateOf(UnselectedBarColor),
+                valueRatio = 0f
+            )
+        }
+
+        val progressBarImage = rule.onNodeWithTag(TEST_TAG).captureToImage()
+        progressBarImage.assertContainsColor(expectedColor = UnselectedBarColor, 1f)
+        progressBarImage.assertDoesNotContainColor(unexpectedColor = SelectedBarColor)
+    }
+
+    @Test
+    public fun directed_value_correct_for_ltr() {
+        val expectedValue = -1
+
+        val value = directedValue(LayoutDirection.Ltr, -1, +1)
+
+        Assert.assertEquals(expectedValue, value)
+    }
+
+    @Test
+    public fun directed_value_correct_for_rtl() {
+        val expectedValue = +1
+
+        val value = directedValue(LayoutDirection.Rtl, -1, +1)
+
+        Assert.assertEquals(expectedValue, value)
+    }
+
+    @Composable
+    internal fun SliderButtonWithDefaults(
+        modifier: Modifier = Modifier,
+        enabled: Boolean = true,
+        onClick: () -> Unit = {},
+        contentAlignment: Alignment = Alignment.Center,
+        buttonControlSize: Dp = ButtonControlSize,
+        content: @Composable () -> Unit = { TestImage() }
+    ) {
+        InlineSliderButton(
+            enabled = enabled,
+            onClick = onClick,
+            contentAlignment = contentAlignment,
+            buttonControlSize = buttonControlSize,
+            modifier = modifier,
+            content = content
+        )
+    }
+
+    @Composable
+    internal fun ProgressBarWithDefaults(
+        modifier: Modifier = Modifier,
+        selectedBarColor: State<Color> = mutableStateOf(SelectedBarColor),
+        unselectedBarColor: State<Color> = mutableStateOf(UnselectedBarColor),
+        barSeparatorColor: State<Color> = mutableStateOf(BarSeparatorColor),
+        visibleSegments: Int = 1,
+        valueRatio: Float = 0.4f
+    ) {
+        val layoutDirection = LayoutDirection.Ltr
+        val drawSelectedProgressBar =
+            { color: Color, ratio: Float, direction: LayoutDirection, drawScope: DrawScope ->
+                drawScope.drawTestSelectedProgressBar(color, ratio, direction)
+            }
+        val drawUnselectedProgressBar =
+            { color: Color, ratio: Float, direction: LayoutDirection, drawScope: DrawScope ->
+                drawScope.drawTestUnselectedProgressBar(color, ratio, direction)
+            }
+        val drawProgressBarSeparator = { color: Color, position: Float, drawScope: DrawScope ->
+            drawScope.drawTestProgressBarSeparator(color, position)
+        }
+
+        Box(
+            modifier = modifier
+                .height(ProgressBarHeight)
+                .fillMaxWidth()
+                .drawProgressBar(
+                    selectedBarColor = selectedBarColor,
+                    unselectedBarColor = unselectedBarColor,
+                    barSeparatorColor = barSeparatorColor,
+                    visibleSegments = visibleSegments,
+                    valueRatio = valueRatio,
+                    direction = layoutDirection,
+                    drawSelectedProgressBar = drawSelectedProgressBar,
+                    drawUnselectedProgressBar = drawUnselectedProgressBar,
+                    drawProgressBarSeparator = drawProgressBarSeparator
+                )
+        )
+    }
+
+    private fun DrawScope.drawTestSelectedProgressBar(
+        color: Color,
+        valueRatio: Float,
+        direction: LayoutDirection
+    ) {
+        drawLine(
+            color,
+            Offset(
+                directedValue(direction, 0f, size.width * (1 - valueRatio)), size.height / 2
+            ),
+            Offset(
+                directedValue(direction, size.width * valueRatio, size.width), size.height / 2
+            ),
+            strokeWidth = size.height
+        )
+    }
+
+    private fun DrawScope.drawTestUnselectedProgressBar(
+        color: Color,
+        valueRatio: Float,
+        direction: LayoutDirection
+    ) {
+        drawLine(
+            color,
+            Offset(
+                directedValue(direction, size.width * valueRatio, 0f), size.height / 2
+            ),
+            Offset(
+                directedValue(direction, size.width, size.width * (1 - valueRatio)), size.height / 2
+            ),
+            strokeWidth = size.height
+        )
+    }
+
+    private fun DrawScope.drawTestProgressBarSeparator(color: Color, position: Float) {
+        drawLine(
+            color,
+            Offset(position, 0f),
+            Offset(position, size.height),
+            strokeWidth = 1.dp.toPx()
+        )
+    }
+
+    private val ButtonControlSize = 36.dp
+    private val ProgressBarHeight = 10.dp
+    private val SelectedBarColor = Color.Red
+    private val UnselectedBarColor = Color.Green
+    private val BarSeparatorColor = Color.Blue
+}
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Slider.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Slider.kt
new file mode 100644
index 0000000..b724910
--- /dev/null
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/Slider.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.materialcore
+
+import androidx.annotation.RestrictTo
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Composable
+public fun InlineSliderButton(
+    enabled: Boolean,
+    onClick: () -> Unit,
+    contentAlignment: Alignment,
+    buttonControlSize: Dp,
+    modifier: Modifier,
+    content: @Composable () -> Unit
+) {
+    Box(
+        modifier = Modifier
+            .width(buttonControlSize)
+            .fillMaxHeight()
+            .clickable(
+                enabled = enabled,
+                onClick = onClick,
+                interactionSource = remember { MutableInteractionSource() },
+                indication = LocalIndication.current,
+            )
+            .then(modifier),
+        contentAlignment = contentAlignment
+    ) {
+        content()
+    }
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Suppress("PrimitiveInLambda")
+public fun Modifier.drawProgressBar(
+    selectedBarColor: State<Color>,
+    unselectedBarColor: State<Color>,
+    barSeparatorColor: State<Color>,
+    visibleSegments: Int,
+    valueRatio: Float,
+    direction: LayoutDirection,
+    drawSelectedProgressBar:
+        (color: Color, valueRatio: Float, direction: LayoutDirection, drawScope: DrawScope) -> Unit,
+    drawUnselectedProgressBar:
+        (color: Color, valueRatio: Float, direction: LayoutDirection, drawScope: DrawScope) -> Unit,
+    drawProgressBarSeparator: (color: Color, position: Float, drawScope: DrawScope) -> Unit,
+): Modifier = drawWithContent {
+    drawUnselectedProgressBar(unselectedBarColor.value, valueRatio, direction, this)
+
+    drawSelectedProgressBar(selectedBarColor.value, valueRatio, direction, this)
+
+    for (separator in 1 until visibleSegments) {
+        val x = separator * size.width / visibleSegments
+        drawProgressBarSeparator(barSeparatorColor.value, x, this)
+    }
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public fun <T> directedValue(layoutDirection: LayoutDirection, ltrValue: T, rtlValue: T): T =
+    if (layoutDirection == LayoutDirection.Ltr) ltrValue else rtlValue
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
index d9985b5..af28aa7 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/RangeDefaults.kt
@@ -17,95 +17,11 @@
 package androidx.wear.compose.material
 
 import androidx.compose.foundation.progressSemantics
-import androidx.compose.material.icons.materialIcon
-import androidx.compose.material.icons.materialPath
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.semantics.disabled
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.setProgress
-import androidx.compose.ui.util.lerp
-import kotlin.math.roundToInt
-
-/**
- * Icons which are used by Range controls like slider and stepper
- */
-internal object RangeIcons {
-
-    /**
-     * An [ImageVector] with a minus sign.
-     */
-    val Minus: ImageVector
-        get() = if (_minus != null) _minus!!
-        else {
-            _minus = materialIcon(name = "MinusIcon") {
-                materialPath {
-                    moveTo(19.0f, 13.0f)
-                    horizontalLineTo(5.0f)
-                    verticalLineToRelative(-2.0f)
-                    horizontalLineToRelative(14.0f)
-                    verticalLineToRelative(2.0f)
-                    close()
-                }
-            }
-            _minus!!
-        }
-
-    private var _minus: ImageVector? = null
-}
-
-/**
- * Defaults used by range controls like slider and stepper
- */
-internal object RangeDefaults {
-    /**
-     * Calculates value of [currentStep] in [valueRange] depending on number of [steps]
-     */
-    fun calculateCurrentStepValue(
-        currentStep: Int,
-        steps: Int,
-        valueRange: ClosedFloatingPointRange<Float>
-    ): Float = lerp(
-        valueRange.start, valueRange.endInclusive,
-        currentStep.toFloat() / (steps + 1).toFloat()
-    ).coerceIn(valueRange)
-
-    /**
-     * Snaps [value] to the closest [step] in the [valueRange]
-     */
-    fun snapValueToStep(
-        value: Float,
-        valueRange: ClosedFloatingPointRange<Float>,
-        steps: Int
-    ): Int = ((value - valueRange.start) /
-        (valueRange.endInclusive - valueRange.start) * (steps + 1))
-        .roundToInt().coerceIn(0, steps + 1)
-}
-
-internal fun Modifier.rangeSemantics(
-    step: Int,
-    enabled: Boolean,
-    @Suppress("PrimitiveInLambda")
-    onValueChange: (Float) -> Unit,
-    valueRange: ClosedFloatingPointRange<Float>,
-    steps: Int
-): Modifier = semantics(mergeDescendants = true) {
-    if (!enabled) disabled()
-    setProgress(
-        action = { targetValue ->
-            val newStepIndex = RangeDefaults.snapValueToStep(targetValue, valueRange, steps)
-            if (step == newStepIndex) {
-                false
-            } else {
-                onValueChange(targetValue)
-                true
-            }
-        }
-    )
-}.progressSemantics(
-    RangeDefaults.calculateCurrentStepValue(step, steps, valueRange),
-    valueRange, steps
-)
+import androidx.wear.compose.materialcore.RangeDefaults
 
 internal fun Modifier.rangeSemantics(
     value: Float,
@@ -115,9 +31,23 @@
     valueRange: ClosedFloatingPointRange<Float>,
     steps: Int
 ): Modifier {
-    val currentStep = RangeDefaults.snapValueToStep(value, valueRange, steps)
-
-    return rangeSemantics(currentStep, enabled, onValueChange, valueRange, steps)
+    val step = RangeDefaults.snapValueToStep(value, valueRange, steps)
+    return semantics(mergeDescendants = true) {
+        if (!enabled) disabled()
+        setProgress(
+            action = { targetValue ->
+                val newStepIndex = RangeDefaults.snapValueToStep(targetValue, valueRange, steps)
+                if (step == newStepIndex) {
+                    false
+                } else {
+                    onValueChange(targetValue)
+                    true
+                }
+            }
+        )
+    }.progressSemantics(
+        RangeDefaults.calculateCurrentStepValue(step, steps, valueRange), valueRange, steps
+    )
 }
 
 internal fun IntProgression.stepsNumber(): Int = (last - first) / step - 1
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Slider.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Slider.kt
index c6614ff..9a474a9 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Slider.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Slider.kt
@@ -19,7 +19,6 @@
 import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
@@ -40,16 +39,17 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
-import androidx.wear.compose.material.RangeDefaults.calculateCurrentStepValue
-import androidx.wear.compose.material.RangeDefaults.snapValueToStep
+import androidx.wear.compose.materialcore.InlineSliderButton
+import androidx.wear.compose.materialcore.RangeDefaults
+import androidx.wear.compose.materialcore.directedValue
+import androidx.wear.compose.materialcore.drawProgressBar
 import kotlin.math.roundToInt
 
 /**
@@ -107,12 +107,18 @@
 ) {
     require(steps >= 0) { "steps should be >= 0" }
     val currentStep =
-        remember(value, valueRange, steps) { snapValueToStep(value, valueRange, steps) }
+        remember(value, valueRange, steps) {
+            RangeDefaults.snapValueToStep(
+                value,
+                valueRange,
+                steps
+            )
+        }
     Box(
         modifier = modifier
             .fillMaxWidth()
             .rangeSemantics(
-                currentStep,
+                value,
                 enabled,
                 onValueChange,
                 valueRange,
@@ -126,7 +132,8 @@
 
         @Suppress("PrimitiveInLambda")
         val updateValue: (Int) -> Unit = { stepDiff ->
-            val newValue = calculateCurrentStepValue(currentStep + stepDiff, steps, valueRange)
+            val newValue =
+                RangeDefaults.calculateCurrentStepValue(currentStep + stepDiff, steps, valueRange)
             if (newValue != value) onValueChange(newValue)
         }
         val selectedBarColor = colors.barColor(enabled, true)
@@ -136,19 +143,25 @@
         Row(
             verticalAlignment = Alignment.CenterVertically,
             horizontalArrangement = Arrangement.Start,
-            modifier = Modifier.fillMaxWidth().background(backgroundColor.value)
+            modifier = Modifier
+                .fillMaxWidth()
+                .background(backgroundColor.value)
         ) {
+            val increaseButtonEnabled = enabled && currentStep < steps + 1
+            val decreaseButtonEnabled = enabled && currentStep > 0
+
             InlineSliderButton(
-                enabled = enabled,
+                enabled = decreaseButtonEnabled,
                 onClick = { updateValue(-1) },
                 contentAlignment = Alignment.CenterStart,
-                modifier = Modifier
-                    .padding(start = InlineSliderDefaults.OuterHorizontalMargin),
-                content = decreaseIcon
+                buttonControlSize = InlineSliderDefaults.ControlSize,
+                modifier = Modifier.padding(start = InlineSliderDefaults.OuterHorizontalMargin),
+                content = { InlineSliderButtonContent(decreaseButtonEnabled, decreaseIcon) }
             )
 
             Box(
-                Modifier.width(InlineSliderDefaults.SpacersWidth)
+                Modifier
+                    .width(InlineSliderDefaults.SpacersWidth)
                     .fillMaxHeight()
                     .background(colors.spacerColor(enabled).value)
             )
@@ -164,25 +177,36 @@
                     .drawProgressBar(
                         selectedBarColor = selectedBarColor,
                         unselectedBarColor = unselectedBarColor,
-                        backgroundColor = backgroundColor,
+                        barSeparatorColor = backgroundColor,
                         visibleSegments = visibleSegments,
                         valueRatio = valueRatio,
-                        direction = LocalLayoutDirection.current
+                        direction = LocalLayoutDirection.current,
+                        drawSelectedProgressBar = { color, ratio, direction, drawScope ->
+                            drawScope.drawSelectedProgressBar(color, ratio, direction)
+                        },
+                        drawUnselectedProgressBar = { color, ratio, direction, drawScope ->
+                            drawScope.drawUnselectedProgressBar(color, ratio, direction)
+                        },
+                        drawProgressBarSeparator = { color, position, drawScope ->
+                            drawScope.drawProgressBarSeparator(color, position)
+                        }
                     )
             )
 
             Box(
-                Modifier.width(InlineSliderDefaults.SpacersWidth)
+                Modifier
+                    .width(InlineSliderDefaults.SpacersWidth)
                     .fillMaxHeight()
                     .background(colors.spacerColor(enabled).value)
             )
 
             InlineSliderButton(
-                enabled = enabled,
+                enabled = increaseButtonEnabled,
                 onClick = { updateValue(1) },
                 contentAlignment = Alignment.CenterEnd,
+                buttonControlSize = InlineSliderDefaults.ControlSize,
                 modifier = Modifier.padding(end = InlineSliderDefaults.OuterHorizontalMargin),
-                content = increaseIcon
+                content = { InlineSliderButtonContent(increaseButtonEnabled, increaseIcon) }
             )
         }
     }
@@ -350,7 +374,7 @@
     /**
      * Decrease [ImageVector]
      */
-    public val Decrease = RangeIcons.Minus
+    public val Decrease = androidx.wear.compose.materialcore.RangeIcons.Minus
 
     /**
      * Increase [ImageVector]
@@ -420,44 +444,13 @@
     }
 }
 
-@Composable
-private fun InlineSliderButton(
-    enabled: Boolean,
-    onClick: () -> Unit,
-    contentAlignment: Alignment,
-    modifier: Modifier,
-    content: @Composable () -> Unit
-) {
-    Box(
-        modifier = Modifier
-            .width(InlineSliderDefaults.ControlSize)
-            .fillMaxHeight()
-            .clickable(
-                enabled = enabled,
-                onClick = onClick,
-                role = Role.Button
-            )
-            .then(modifier),
-        contentAlignment = contentAlignment
-    ) {
-        CompositionLocalProvider(
-            LocalContentAlpha provides
-                if (enabled) LocalContentAlpha.current else ContentAlpha.disabled,
-            content = content
-        )
-    }
-}
-
-private fun Modifier.drawProgressBar(
-    selectedBarColor: State<Color>,
-    unselectedBarColor: State<Color>,
-    backgroundColor: State<Color>,
-    visibleSegments: Int,
+private fun DrawScope.drawSelectedProgressBar(
+    color: Color,
     valueRatio: Float,
-    direction: LayoutDirection,
-): Modifier = drawWithContent {
+    direction: LayoutDirection
+) {
     drawLine(
-        selectedBarColor.value,
+        color,
         Offset(
             directedValue(direction, 0f, size.width * (1 - valueRatio)), size.height / 2
         ),
@@ -466,8 +459,15 @@
         ),
         strokeWidth = InlineSliderDefaults.BarHeight.toPx()
     )
+}
+
+private fun DrawScope.drawUnselectedProgressBar(
+    color: Color,
+    valueRatio: Float,
+    direction: LayoutDirection,
+) {
     drawLine(
-        unselectedBarColor.value,
+        color,
         Offset(
             directedValue(direction, size.width * valueRatio, 0f), size.height / 2
         ),
@@ -476,16 +476,23 @@
         ),
         strokeWidth = InlineSliderDefaults.BarHeight.toPx()
     )
-    for (separator in 1 until visibleSegments) {
-        val x = separator * size.width / visibleSegments
-        drawLine(
-            backgroundColor.value,
-            Offset(x, size.height / 2 - InlineSliderDefaults.BarHeight.toPx() / 2),
-            Offset(x, size.height / 2 + InlineSliderDefaults.BarHeight.toPx() / 2),
-            strokeWidth = InlineSliderDefaults.BarSeparatorWidth.toPx()
-        )
-    }
 }
 
-private fun <T> directedValue(layoutDirection: LayoutDirection, ltrValue: T, rtlValue: T): T =
-    if (layoutDirection == LayoutDirection.Ltr) ltrValue else rtlValue
+private fun DrawScope.drawProgressBarSeparator(color: Color, position: Float) {
+    drawLine(
+        color,
+        Offset(position, size.height / 2 - InlineSliderDefaults.BarHeight.toPx() / 2),
+        Offset(position, size.height / 2 + InlineSliderDefaults.BarHeight.toPx() / 2),
+        strokeWidth = InlineSliderDefaults.BarSeparatorWidth.toPx()
+    )
+}
+
+@Composable
+private fun InlineSliderButtonContent(
+    enabled: Boolean,
+    content: @Composable () -> Unit
+) = CompositionLocalProvider(
+    LocalContentAlpha provides
+        if (enabled) LocalContentAlpha.current else ContentAlpha.disabled,
+    content = content
+)
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
index 7de734f..32477ab 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoActivity.kt
@@ -146,9 +146,9 @@
                 (navigator.backStack + navigator.currentDemo).map { it.title }
             },
             restore = { restored ->
-                require(restored.isNotEmpty())
+                require(restored.isNotEmpty()) { "restored demo is empty" }
                 val backStack = restored.mapTo(mutableListOf()) {
-                    requireNotNull(findDemo(rootDemo, it))
+                    requireNotNull(findDemo(rootDemo, it)) { "No root demo" }
                 }
                 val initial = backStack.removeAt(backStack.lastIndex)
                 Navigator(backDispatcher, launchActivityDemo, rootDemo, initial, backStack)
diff --git a/wear/protolayout/protolayout-expression-pipeline/api/current.txt b/wear/protolayout/protolayout-expression-pipeline/api/current.txt
index efe9106..8bf3f6e 100644
--- a/wear/protolayout/protolayout-expression-pipeline/api/current.txt
+++ b/wear/protolayout/protolayout-expression-pipeline/api/current.txt
@@ -54,7 +54,7 @@
   }
 
   public interface PlatformDataReceiver {
-    method public void onData(java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public void onData(androidx.wear.protolayout.expression.PlatformDataValues);
     method public void onInvalidated(java.util.Set<androidx.wear.protolayout.expression.PlatformDataKey<?>!>);
   }
 
@@ -69,9 +69,9 @@
   }
 
   public final class StateStore {
-    method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
     method public static int getMaxStateEntryCount();
-    method @UiThread public void setAppStateEntryValues(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method @UiThread public void setAppStateEntryValues(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
   }
 
 }
diff --git a/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt b/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
index 8f88cd8..cf9b07c 100644
--- a/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression-pipeline/api/restricted_current.txt
@@ -54,7 +54,7 @@
   }
 
   public interface PlatformDataReceiver {
-    method public void onData(java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public void onData(androidx.wear.protolayout.expression.PlatformDataValues);
     method public void onInvalidated(java.util.Set<androidx.wear.protolayout.expression.PlatformDataKey<?>!>);
   }
 
@@ -70,9 +70,9 @@
 
   public final class StateStore {
     ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public StateStore(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue!>);
-    method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public static androidx.wear.protolayout.expression.pipeline.StateStore create(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
     method public static int getMaxStateEntryCount();
-    method @UiThread public void setAppStateEntryValues(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method @UiThread public void setAppStateEntryValues(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @UiThread public void setAppStateEntryValuesProto(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue!>);
   }
 
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
index 51a9ee7..7c56ec2 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataProvider.java
@@ -19,7 +19,6 @@
 import androidx.annotation.NonNull;
 import androidx.wear.protolayout.expression.PlatformDataKey;
 
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -27,32 +26,29 @@
  * This interface is used by platform data providers to yield dynamic data for their supported data
  * keys.
  *
- * <p>It's up to the implementations to check if the expression provider has the required
- * permission before sending data with {@link PlatformDataReceiver#onData(Map)}. If a required
- * permission is not granted or is revoked they should stop sending more data and call
- * {@link PlatformDataReceiver#onInvalidated(Set)} instead.
+ * <p>It's up to the implementations to check if the expression provider has the required permission
+ * before sending data with {@link PlatformDataReceiver#onData}. If a required permission is not
+ * granted or is revoked they should stop sending more data and call {@link
+ * PlatformDataReceiver#onInvalidated(Set)} instead.
  */
 public interface PlatformDataProvider {
     /**
      * Sets the receiver for receiving the platform data from this provider.
      *
-     * <p>Each provider is expected to have only one receiver. When a receiver has already been
-     * set, the implementation should throw an exception.
+     * <p>Each provider is expected to have only one receiver. When a receiver has already been set,
+     * the implementation should throw an exception.
      *
-     * <p>The implementation should periodically send the dynamic data values for the set of
-     * {@link PlatformDataKey}s specified when registering this {@link PlatformDataProvider} in
-     * {@link DynamicTypeEvaluator.Config.Builder#addPlatformDataProvider}
+     * <p>The implementation should periodically send the dynamic data values for the set of {@link
+     * PlatformDataKey}s specified when registering this {@link PlatformDataProvider} in {@link
+     * DynamicTypeEvaluator.Config.Builder#addPlatformDataProvider}
      *
-     * @param executor The executor to run the {@link PlatformDataReceiver#onData(Map)} or
-     *                 {@link PlatformDataReceiver#onInvalidated(Set)} on.
-     * @param receiver The {@link PlatformDataReceiver} to receive the new dynamic values or to
-     *                 be notified that the current data has been invalidated for the registered
-     *                 keys.
+     * @param executor The executor to run the {@link PlatformDataReceiver#onData} or {@link
+     *     PlatformDataReceiver#onInvalidated(Set)} on.
+     * @param receiver The {@link PlatformDataReceiver} to receive the new dynamic values or to be
+     *     notified that the current data has been invalidated for the registered keys.
      */
     void setReceiver(@NonNull Executor executor, @NonNull PlatformDataReceiver receiver);
 
-    /**
-     * Clears the receiver from the provider.
-     */
+    /** Clears the receiver from the provider. */
     void clearReceiver();
 }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
index 8a9b619..83b0336 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataReceiver.java
@@ -17,28 +17,25 @@
 package androidx.wear.protolayout.expression.pipeline;
 
 import androidx.annotation.NonNull;
-import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
+import androidx.wear.protolayout.expression.PlatformDataValues;
 import androidx.wear.protolayout.expression.PlatformDataKey;
 
-import java.util.Map;
 import java.util.Set;
 
-/**
- * Callback for receiving a PlatformDataProvider's new data.
- */
+/** Callback for receiving a PlatformDataProvider's new data. */
 public interface PlatformDataReceiver {
 
     /**
-     * Called by the registered {@ilnk PlatformDataProvider} to send new values.
+     * Called by the registered {@link PlatformDataProvider} to send new values.
      *
      * @param newData The new values for the registered keys.
      */
-    void onData(@NonNull Map<PlatformDataKey<?>, DynamicDataValue> newData);
+    void onData(@NonNull PlatformDataValues newData);
 
     /**
-     * Called by the registered {@ilnk PlatformDataProvider} to notify that the current data has
-     * been invalidated. Typically, this invalidated status is transient and subsequent onData
-     * call can be followed to sent new values.
+     * Called by the registered {@link PlatformDataProvider} to notify that the current data has
+     * been invalidated. Typically, this invalidated status is transient and subsequent onData call
+     * can be followed to sent new values.
      *
      * @param keys The set of keys with current data been invalidated.
      */
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java
index 8c7b1ab..9014ce5 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStore.java
@@ -26,9 +26,9 @@
 import androidx.annotation.UiThread;
 import androidx.collection.ArrayMap;
 import androidx.collection.ArraySet;
-import androidx.wear.protolayout.expression.DynamicDataBuilders;
 import androidx.wear.protolayout.expression.DynamicDataKey;
 import androidx.wear.protolayout.expression.PlatformDataKey;
+import androidx.wear.protolayout.expression.PlatformDataValues;
 import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
 
 import java.util.Collections;
@@ -75,11 +75,11 @@
      *
      * <p>Informs registered listeners of changed values.
      */
-    void updatePlatformDataEntries(
-            @NonNull Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> newData) {
+    void updatePlatformDataEntries(@NonNull PlatformDataValues newData) {
         updatePlatformDataEntriesProto(
-                newData.entrySet().stream().collect(toMap(
-                        Map.Entry::getKey, entry -> entry.getValue().toDynamicDataValueProto()))
+                newData.getAll().entrySet().stream().collect(toMap(
+                        entry -> (PlatformDataKey<?>)entry.getKey(),
+                        entry -> entry.getValue().toDynamicDataValueProto()))
         );
     }
 
@@ -188,10 +188,7 @@
                 mUiExecutor,
                 new PlatformDataReceiver() {
                     @Override
-                    public void onData(
-                            @NonNull
-                            Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue>
-                                    newData) {
+                    public void onData(@NonNull PlatformDataValues newData) {
                         updatePlatformDataEntries(newData);
                     }
 
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
index 93d2a9c..310ab9f 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/main/java/androidx/wear/protolayout/expression/pipeline/StateStore.java
@@ -67,7 +67,7 @@
      */
     @NonNull
     public static StateStore create(
-            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue>
+            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue<?>>
                     initialState) {
         return new StateStore(toProto(initialState));
     }
@@ -92,7 +92,7 @@
      */
     @UiThread
     public void setAppStateEntryValues(
-            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue> newState) {
+            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue<?>> newState) {
         setAppStateEntryValuesProto(toProto(newState));
     }
 
@@ -194,7 +194,7 @@
 
     @NonNull
     private static Map<AppDataKey<?>, DynamicDataValue> toProto(
-            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue> value) {
+            @NonNull Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue<?>> value) {
         return value.entrySet().stream()
                 .collect(toMap(Entry::getKey, entry -> entry.getValue().toDynamicDataValueProto()));
     }
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
index 0962e77..43ff081 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/FloatNodeTest.java
@@ -32,6 +32,7 @@
 import androidx.wear.protolayout.expression.AppDataKey;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
 import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.PlatformDataValues;
 import androidx.wear.protolayout.expression.pipeline.FloatNodes.AnimatableFixedFloatNode;
 import androidx.wear.protolayout.expression.pipeline.FloatNodes.ArithmeticFloatNode;
 import androidx.wear.protolayout.expression.pipeline.FloatNodes.DynamicAnimatedFloatNode;
@@ -164,14 +165,16 @@
         verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
 
         PlatformDataReceiver receiver = receiverCaptor.getValue();
-        receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
-                DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        HEART_RATE_BPM, DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
 
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(70.0f);
 
-        receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
-                DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        HEART_RATE_BPM, DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
 
         assertThat(results).hasSize(2);
         assertThat(results).containsExactly(70.0f, 80.0f);
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
index c3a90ce..ae9968b 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/Int32NodesTest.java
@@ -33,6 +33,7 @@
 import androidx.wear.protolayout.expression.AppDataKey;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
 import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.PlatformDataValues;
 import androidx.wear.protolayout.expression.PlatformHealthSources;
 import androidx.wear.protolayout.expression.pipeline.Int32Nodes.AnimatableFixedInt32Node;
 import androidx.wear.protolayout.expression.pipeline.Int32Nodes.DynamicAnimatedInt32Node;
@@ -258,13 +259,15 @@
         verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
 
         PlatformDataReceiver receiver = receiverCaptor.getValue();
-        receiver.onData(ImmutableMap.of(DAILY_STEPS,
-                DynamicDataBuilders.DynamicDataValue.fromInt(70)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        DAILY_STEPS, DynamicDataBuilders.DynamicDataValue.fromInt(70)));
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(70);
 
-        receiver.onData(ImmutableMap.of(DAILY_STEPS,
-                DynamicDataBuilders.DynamicDataValue.fromInt(80)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        DAILY_STEPS, DynamicDataBuilders.DynamicDataValue.fromInt(80)));
         assertThat(results).hasSize(2);
         assertThat(results).containsExactly(70, 80);
     }
@@ -428,14 +431,16 @@
         verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
 
         PlatformDataReceiver receiver = receiverCaptor.getValue();
-        receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
-                DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        HEART_RATE_BPM, DynamicDataBuilders.DynamicDataValue.fromFloat(70.0f)));
 
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(70);
 
-        receiver.onData(ImmutableMap.of(HEART_RATE_BPM,
-                DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        HEART_RATE_BPM, DynamicDataBuilders.DynamicDataValue.fromFloat(80.0f)));
 
         assertThat(results).hasSize(2);
         assertThat(results).containsExactly(70, 80);
@@ -467,14 +472,16 @@
         verify(mMockDataProvider).setReceiver(any(), receiverCaptor.capture());
 
         PlatformDataReceiver receiver = receiverCaptor.getValue();
-        receiver.onData(ImmutableMap.of(DAILY_STEPS,
-                DynamicDataBuilders.DynamicDataValue.fromInt(70)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        DAILY_STEPS, DynamicDataBuilders.DynamicDataValue.fromInt(70)));
 
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(70);
 
-        receiver.onData(ImmutableMap.of(DAILY_STEPS,
-                DynamicDataBuilders.DynamicDataValue.fromInt(80)));
+        receiver.onData(
+                PlatformDataValues.of(
+                        DAILY_STEPS, DynamicDataBuilders.DynamicDataValue.fromInt(80)));
 
         assertThat(results).hasSize(2);
         assertThat(results).containsExactly(70, 80);
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java
index ecfea31..ed58ef8 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/PlatformDataStoreTest.java
@@ -20,13 +20,12 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.util.ArrayMap;
-
 import androidx.annotation.NonNull;
 import androidx.collection.ArraySet;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.wear.protolayout.expression.DynamicBuilders;
 import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.PlatformDataValues;
 import androidx.wear.protolayout.expression.PlatformDataKey;
 import androidx.wear.protolayout.expression.proto.DynamicDataProto.DynamicDataValue;
 import androidx.wear.protolayout.expression.proto.FixedProto;
@@ -98,11 +97,14 @@
         mExpect.that(mDataProvider.mRegisterCount).isEqualTo(1);
 
         mDataProvider.updateValues(
-                Map.of(KEY_FOO_PLATFORM,
-                        DynamicDataBuilders.DynamicDataValue.fromString("newFooValue"),
-                        KEY_BAZ_PLATFORM,
-                        DynamicDataBuilders.DynamicDataValue.fromString("newBazValue")
-                ));
+                new PlatformDataValues.Builder()
+                        .put(
+                                KEY_FOO_PLATFORM,
+                                DynamicDataBuilders.DynamicDataValue.fromString("newFooValue"))
+                        .put(
+                                KEY_BAZ_PLATFORM,
+                                DynamicDataBuilders.DynamicDataValue.fromString("newBazValue"))
+                        .build());
         verify(cbFoo, times(2)).onPreUpdate();
         verify(cbFoo2).onPreUpdate();
         verify(cbBaz).onPreUpdate();
@@ -111,10 +113,9 @@
         verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
 
         mDataProvider.updateValues(
-                Map.of(
+                PlatformDataValues.of(
                         KEY_BAZ_PLATFORM,
-                        DynamicDataBuilders.DynamicDataValue.fromString("updatedBazValue")
-                ));
+                        DynamicDataBuilders.DynamicDataValue.fromString("updatedBazValue")));
         verify(cbFoo, times(1)).onData(buildDynamicDataValue("newFooValue"));
         verify(cbFoo2, times(1)).onData(buildDynamicDataValue("newFooValue"));
         verify(cbBaz).onData(buildDynamicDataValue("newBazValue"));
@@ -144,8 +145,7 @@
 
         private PlatformDataReceiver mRegisteredCallback = null;
 
-        private final Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> mCurrentValue =
-                new ArrayMap<>();
+        private final PlatformDataValues.Builder mCurrentValue = new PlatformDataValues.Builder();
 
         private final Set<PlatformDataKey<?>> mSupportedKeys = new ArraySet<>();
 
@@ -155,20 +155,16 @@
             mSupportedKeys.add(KEY_FOO_PLATFORM);
             mSupportedKeys.add(KEY_BAZ_PLATFORM);
             mCurrentValue.put(
-                    KEY_FOO_PLATFORM,
-                    DynamicDataBuilders.DynamicDataValue.fromString("fooValue")
-            );
+                    KEY_FOO_PLATFORM, DynamicDataBuilders.DynamicDataValue.fromString("fooValue"));
             mCurrentValue.put(
-                    KEY_BAZ_PLATFORM,
-                    DynamicDataBuilders.DynamicDataValue.fromString("bazValue")
-            );
+                    KEY_BAZ_PLATFORM, DynamicDataBuilders.DynamicDataValue.fromString("bazValue"));
         }
 
         public void updateValues(
-                @NonNull Map<PlatformDataKey<?>, DynamicDataBuilders.DynamicDataValue> newData) {
+                @NonNull PlatformDataValues newData) {
             mCurrentValue.putAll(newData);
             if (mRegisteredCallback != null) {
-                mRegisteredCallback.onData(mCurrentValue);
+                mRegisteredCallback.onData(mCurrentValue.build());
             }
         }
 
@@ -178,7 +174,7 @@
                 @NonNull PlatformDataReceiver callback) {
             mRegisterCount++;
             mRegisteredCallback = callback;
-            executor.execute(() -> callback.onData(mCurrentValue));
+            executor.execute(() -> callback.onData(mCurrentValue.build()));
         }
 
         @Override
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
index f803991..c3e9f7f 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/StateStoreTest.java
@@ -74,7 +74,7 @@
 
     @Test
     public void initState_largeNumberOfEntries_throws() {
-        Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue> state = new HashMap<>();
+        Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue<?>> state = new HashMap<>();
         for (int i = 0; i < StateStore.getMaxStateEntryCount() + 10; i++) {
             state.put(
                     new AppDataKey<DynamicString>(Integer.toString(i)),
@@ -85,7 +85,7 @@
 
     @Test
     public void newState_largeNumberOfEntries_throws() {
-        Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue> state = new HashMap<>();
+        Map<AppDataKey<?>, DynamicDataBuilders.DynamicDataValue<?>> state = new HashMap<>();
         for (int i = 0; i < StateStore.getMaxStateEntryCount() + 10; i++) {
             state.put(
                     new AppDataKey<DynamicString>(Integer.toString(i)),
diff --git a/wear/protolayout/protolayout-expression/api/current.txt b/wear/protolayout/protolayout-expression/api/current.txt
index aa2fced..1203940 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -288,14 +288,14 @@
   public final class DynamicDataBuilders {
   }
 
-  public static interface DynamicDataBuilders.DynamicDataValue {
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromBool(boolean);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromByteArray(byte[]);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromByteArray(byte[], int, int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromColor(@ColorInt int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromFloat(float);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromInt(int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromString(String);
+  public static interface DynamicDataBuilders.DynamicDataValue<T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> {
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool!> fromBool(boolean);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?> fromByteArray(byte[]);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?> fromByteArray(byte[], int, int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor!> fromColor(@ColorInt int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> fromFloat(float);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32!> fromInt(int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicString!> fromString(String);
     method public default byte[] toDynamicDataValueByteArray();
     method public default int toDynamicDataValueByteArray(byte[]);
     method public default int toDynamicDataValueByteArray(byte[], int, int);
@@ -313,6 +313,17 @@
     ctor public PlatformDataKey(String, String);
   }
 
+  public final class PlatformDataValues {
+    method public java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!> getAll();
+    method public static <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.expression.PlatformDataValues of(androidx.wear.protolayout.expression.PlatformDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
+  }
+
+  public static final class PlatformDataValues.Builder {
+    ctor public PlatformDataValues.Builder();
+    method public androidx.wear.protolayout.expression.PlatformDataValues build();
+    method public <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.expression.PlatformDataValues.Builder put(androidx.wear.protolayout.expression.PlatformDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
+  }
+
   public class PlatformHealthSources {
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyCalories();
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceMeters();
@@ -320,24 +331,17 @@
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 dailySteps();
     method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy heartRateAccuracy();
     method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat heartRateBpm();
-  }
-
-  public static class PlatformHealthSources.Constants {
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_HIGH;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_LOW;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_MEDIUM;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE;
+    field public static final int HEART_RATE_ACCURACY_HIGH = 5; // 0x5
+    field public static final int HEART_RATE_ACCURACY_LOW = 3; // 0x3
+    field public static final int HEART_RATE_ACCURACY_MEDIUM = 4; // 0x4
+    field public static final int HEART_RATE_ACCURACY_NO_CONTACT = 1; // 0x1
+    field public static final int HEART_RATE_ACCURACY_UNKNOWN = 0; // 0x0
+    field public static final int HEART_RATE_ACCURACY_UNRELIABLE = 2; // 0x2
   }
 
   public static final class PlatformHealthSources.DynamicHeartRateAccuracy implements androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 {
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy HIGH;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy LOW;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy MEDIUM;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy NO_CONTACT;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNKNOWN;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNRELIABLE;
+    method public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy constant(int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy!> dynamicDataValueOf(int);
   }
 
   public static class PlatformHealthSources.Keys {
diff --git a/wear/protolayout/protolayout-expression/api/restricted_current.txt b/wear/protolayout/protolayout-expression/api/restricted_current.txt
index aa2fced..1203940 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -288,14 +288,14 @@
   public final class DynamicDataBuilders {
   }
 
-  public static interface DynamicDataBuilders.DynamicDataValue {
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromBool(boolean);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromByteArray(byte[]);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromByteArray(byte[], int, int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromColor(@ColorInt int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromFloat(float);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromInt(int);
-    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue fromString(String);
+  public static interface DynamicDataBuilders.DynamicDataValue<T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> {
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool!> fromBool(boolean);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?> fromByteArray(byte[]);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?> fromByteArray(byte[], int, int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor!> fromColor(@ColorInt int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat!> fromFloat(float);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32!> fromInt(int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.DynamicBuilders.DynamicString!> fromString(String);
     method public default byte[] toDynamicDataValueByteArray();
     method public default int toDynamicDataValueByteArray(byte[]);
     method public default int toDynamicDataValueByteArray(byte[], int, int);
@@ -313,6 +313,17 @@
     ctor public PlatformDataKey(String, String);
   }
 
+  public final class PlatformDataValues {
+    method public java.util.Map<androidx.wear.protolayout.expression.PlatformDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!> getAll();
+    method public static <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.expression.PlatformDataValues of(androidx.wear.protolayout.expression.PlatformDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
+  }
+
+  public static final class PlatformDataValues.Builder {
+    ctor public PlatformDataValues.Builder();
+    method public androidx.wear.protolayout.expression.PlatformDataValues build();
+    method public <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.expression.PlatformDataValues.Builder put(androidx.wear.protolayout.expression.PlatformDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
+  }
+
   public class PlatformHealthSources {
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyCalories();
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat dailyDistanceMeters();
@@ -320,24 +331,17 @@
     method @RequiresPermission(android.Manifest.permission.ACTIVITY_RECOGNITION) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 dailySteps();
     method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy heartRateAccuracy();
     method @RequiresPermission(android.Manifest.permission.BODY_SENSORS) public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat heartRateBpm();
-  }
-
-  public static class PlatformHealthSources.Constants {
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_HIGH;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_LOW;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_MEDIUM;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN;
-    field public static final androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE;
+    field public static final int HEART_RATE_ACCURACY_HIGH = 5; // 0x5
+    field public static final int HEART_RATE_ACCURACY_LOW = 3; // 0x3
+    field public static final int HEART_RATE_ACCURACY_MEDIUM = 4; // 0x4
+    field public static final int HEART_RATE_ACCURACY_NO_CONTACT = 1; // 0x1
+    field public static final int HEART_RATE_ACCURACY_UNKNOWN = 0; // 0x0
+    field public static final int HEART_RATE_ACCURACY_UNRELIABLE = 2; // 0x2
   }
 
   public static final class PlatformHealthSources.DynamicHeartRateAccuracy implements androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32 {
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy HIGH;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy LOW;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy MEDIUM;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy NO_CONTACT;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNKNOWN;
-    field public static final androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy UNRELIABLE;
+    method public static androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy constant(int);
+    method public static androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy!> dynamicDataValueOf(int);
   }
 
   public static class PlatformHealthSources.Keys {
diff --git a/wear/protolayout/protolayout-expression/build.gradle b/wear/protolayout/protolayout-expression/build.gradle
index f0bf70b..85d4ee8 100644
--- a/wear/protolayout/protolayout-expression/build.gradle
+++ b/wear/protolayout/protolayout-expression/build.gradle
@@ -26,6 +26,7 @@
     api("androidx.annotation:annotation:1.2.0")
 
     implementation("androidx.annotation:annotation-experimental:1.3.0")
+    implementation("androidx.collection:collection:1.2.0")
     implementation(project(path: ":wear:protolayout:protolayout-proto", configuration: "shadow"))
 
     // Upgrade transitive kotlin-stdlib dependency from annotation-experimental.
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
index 15ef422..ec4913e 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicDataBuilders.java
@@ -21,6 +21,12 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicType;
 import androidx.wear.protolayout.expression.FixedValueBuilders.FixedBool;
 import androidx.wear.protolayout.expression.FixedValueBuilders.FixedColor;
 import androidx.wear.protolayout.expression.FixedValueBuilders.FixedFloat;
@@ -35,165 +41,166 @@
 
 /** Builders for dynamic data value of a provider. */
 public final class DynamicDataBuilders {
-  private DynamicDataBuilders() {}
+    private DynamicDataBuilders() {}
 
-  /**
-   * Interface defining a dynamic data value.
-   *
-   * @since 1.2
-   */
-  public interface DynamicDataValue {
-    /** Get the protocol buffer representation of this object. */
+    /**
+     * Interface defining a dynamic data value.
+     *
+     * @since 1.2
+     */
+    public interface DynamicDataValue<T extends DynamicType> {
+        /** Get the protocol buffer representation of this object. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        DynamicDataProto.DynamicDataValue toDynamicDataValueProto();
+
+        /**
+         * Creates a {@link DynamicDataValue} from a byte array generated by {@link
+         * #toDynamicDataValueByteArray()}.
+         *
+         * @throws IllegalArgumentException if the byte array does not contain a valid serialization
+         */
+        @NonNull
+        static DynamicDataValue<?> fromByteArray(@NonNull byte[] byteArray) {
+            return fromByteArray(byteArray, 0, byteArray.length);
+        }
+
+        /**
+         * Creates a {@link DynamicDataValue} from the provided byte array at the provided offset
+         * and length, that was generated by one of the {@link #toDynamicDataValueByteArray}
+         * overloads.
+         *
+         * @throws IllegalArgumentException if the byte array does not contain a valid serialization
+         *     in the provided offset and length
+         */
+        @NonNull
+        static DynamicDataValue<?> fromByteArray(
+                @NonNull byte[] byteArray, int offset, int length) {
+            try {
+                return dynamicDataValueFromProto(
+                        DynamicDataProto.DynamicDataValue.parseFrom(
+                                CodedInputStream.newInstance(byteArray, offset, length),
+                                ExtensionRegistryLite.getEmptyRegistry()));
+            } catch (IOException e) {
+                throw new IllegalArgumentException(
+                        "Byte array could not be parsed into DynamicDataValue", e);
+            }
+        }
+
+        /**
+         * Serializes the {@link DynamicDataValue} into a new byte array that can later be used with
+         * {@link #fromByteArray(byte[])}.
+         */
+        @NonNull
+        default byte[] toDynamicDataValueByteArray() {
+            return toDynamicDataValueProto().toByteArray();
+        }
+
+        /**
+         * Serializes the {@link DynamicDataValue} into the provided byte array, returning the
+         * amount of bytes written, that can later be used with {@code
+         * DynamicDataValue.fromByteArray(byteArray, 0, bytesWritten)}.
+         *
+         * @throws IllegalArgumentException if the byte array is too small
+         */
+        default int toDynamicDataValueByteArray(@NonNull byte[] byteArray) {
+            return toDynamicDataValueByteArray(byteArray, 0, byteArray.length);
+        }
+
+        /**
+         * Serializes the {@link DynamicDataValue} into the provided byte array, returning the
+         * amount of bytes written, limited by the provided offset and length, that can later be
+         * used with {@code DynamicDataValue.fromByteArray(byteArray, offset, bytesWritten)}.
+         *
+         * @throws IllegalArgumentException if the byte array is too small
+         */
+        default int toDynamicDataValueByteArray(@NonNull byte[] byteArray, int offset, int length) {
+            CodedOutputStream stream = CodedOutputStream.newInstance(byteArray, offset, length);
+            try {
+                toDynamicDataValueProto().writeTo(stream);
+            } catch (IOException e) {
+                throw new IllegalArgumentException(
+                        "Provided byte array not large enough to contain this DynamicDataValue", e);
+            }
+            return stream.getTotalBytesWritten();
+        }
+
+        /** Creates a boolean {@link DynamicDataValue}. */
+        @NonNull
+        static DynamicDataValue<DynamicBool> fromBool(boolean constant) {
+            return new FixedBool.Builder().setValue(constant).build();
+        }
+
+        /** Creates a int {@link DynamicDataValue}. */
+        @NonNull
+        static DynamicDataValue<DynamicInt32> fromInt(int constant) {
+            return new FixedInt32.Builder().setValue(constant).build();
+        }
+
+        /** Creates a float {@link DynamicDataValue}. */
+        @NonNull
+        static DynamicDataValue<DynamicFloat> fromFloat(float constant) {
+            return new FixedFloat.Builder().setValue(constant).build();
+        }
+
+        /** Creates a color {@link DynamicDataValue}. */
+        @NonNull
+        static DynamicDataValue<DynamicColor> fromColor(@ColorInt int constant) {
+            return new FixedColor.Builder().setArgb(constant).build();
+        }
+
+        /** Creates a string {@link DynamicDataValue}. */
+        @NonNull
+        static DynamicDataValue<DynamicString> fromString(@NonNull String constant) {
+            return new FixedString.Builder().setValue(constant).build();
+        }
+
+        /** Get the fingerprint for this object or null if unknown. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        Fingerprint getFingerprint();
+
+        /** Builder to create {@link DynamicDataValue} objects. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        interface Builder <T extends DynamicType> {
+
+            /** Builds an instance with values accumulated in this Builder. */
+            @NonNull
+            DynamicDataValue<T> build();
+        }
+    }
+
+    /**
+     * Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
+     * created using this method can't be added to any other wrapper.
+     */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
-    DynamicDataProto.DynamicDataValue toDynamicDataValueProto();
-
-    /**
-     * Creates a {@link DynamicDataValue} from a byte array generated by {@link
-     * #toDynamicDataValueByteArray()}.
-     *
-     * @throws IllegalArgumentException if the byte array does not contain a valid serialization
-     */
-    @NonNull
-    static DynamicDataValue fromByteArray(@NonNull byte[] byteArray) {
-      return fromByteArray(byteArray, 0, byteArray.length);
+    public static DynamicDataValue<?> dynamicDataValueFromProto(
+            @NonNull DynamicDataProto.DynamicDataValue proto) {
+        return dynamicDataValueFromProto(proto, null);
     }
 
-    /**
-     * Creates a {@link DynamicDataValue} from the provided byte array at the provided offset and
-     * length, that was generated by one of the {@link #toDynamicDataValueByteArray} overloads.
-     *
-     * @throws IllegalArgumentException if the byte array does not contain a valid serialization in
-     *     the provided offset and length
-     */
-    @NonNull
-    static DynamicDataValue fromByteArray(@NonNull byte[] byteArray, int offset, int length) {
-      try {
-        return dynamicDataValueFromProto(
-                DynamicDataProto.DynamicDataValue.parseFrom(
-                        CodedInputStream.newInstance(byteArray, offset, length),
-                        ExtensionRegistryLite.getEmptyRegistry()));
-      } catch (IOException e) {
-        throw new IllegalArgumentException(
-                "Byte array could not be parsed into DynamicDataValue", e);
-      }
-    }
-
-    /**
-     * Serializes the {@link DynamicDataValue} into a new byte array that can later be used with
-     * {@link #fromByteArray(byte[])}.
-     */
-    @NonNull
-    default byte[] toDynamicDataValueByteArray() {
-      return toDynamicDataValueProto().toByteArray();
-    }
-
-    /**
-     * Serializes the {@link DynamicDataValue} into the provided byte array, returning the amount of
-     * bytes written, that can later be used with {@code DynamicDataValue.fromByteArray(byteArray,
-     * 0, bytesWritten)}.
-     *
-     * @throws IllegalArgumentException if the byte array is too small
-     */
-    default int toDynamicDataValueByteArray(@NonNull byte[] byteArray) {
-      return toDynamicDataValueByteArray(byteArray, 0, byteArray.length);
-    }
-
-    /**
-     * Serializes the {@link DynamicDataValue} into the provided byte array, returning the amount of
-     * bytes written, limited by the provided offset and length, that can later be used with {@code
-     * DynamicDataValue.fromByteArray(byteArray, offset, bytesWritten)}.
-     *
-     * @throws IllegalArgumentException if the byte array is too small
-     */
-    default int toDynamicDataValueByteArray(@NonNull byte[] byteArray, int offset, int length) {
-      CodedOutputStream stream = CodedOutputStream.newInstance(byteArray, offset, length);
-      try {
-        toDynamicDataValueProto().writeTo(stream);
-      } catch (IOException e) {
-        throw new IllegalArgumentException(
-                "Provided byte array not large enough to contain this DynamicDataValue", e);
-      }
-      return stream.getTotalBytesWritten();
-    }
-
-    /** Creates a boolean {@link DynamicDataValue}. */
-    @NonNull
-    static DynamicDataValue fromBool(boolean constant) {
-      return new FixedBool.Builder().setValue(constant).build();
-    }
-
-    /** Creates a int {@link DynamicDataValue}. */
-    @NonNull
-    static DynamicDataValue fromInt(int constant) {
-      return new FixedInt32.Builder().setValue(constant).build();
-    }
-
-    /** Creates a float {@link DynamicDataValue}. */
-    @NonNull
-    static DynamicDataValue fromFloat(float constant) {
-      return new FixedFloat.Builder().setValue(constant).build();
-    }
-
-    /** Creates a color {@link DynamicDataValue}. */
-    @NonNull
-    static DynamicDataValue fromColor(@ColorInt int constant) {
-      return new FixedColor.Builder().setArgb(constant).build();
-    }
-
-    /** Creates a string {@link DynamicDataValue}. */
-    @NonNull
-    static DynamicDataValue fromString(@NonNull String constant) {
-      return new FixedString.Builder().setValue(constant).build();
-    }
-
-    /** Get the fingerprint for this object or null if unknown. */
+    /** Creates a new wrapper instance from the proto. */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    Fingerprint getFingerprint();
-
-    /** Builder to create {@link DynamicDataValue} objects. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    interface Builder {
-
-      /** Builds an instance with values accumulated in this Builder. */
-      @NonNull
-      DynamicDataValue build();
+    @NonNull
+    public static DynamicDataValue<?> dynamicDataValueFromProto(
+            @NonNull DynamicDataProto.DynamicDataValue proto, @Nullable Fingerprint fingerprint) {
+        if (proto.hasStringVal()) {
+            return FixedString.fromProto(proto.getStringVal(), fingerprint);
+        }
+        if (proto.hasInt32Val()) {
+            return FixedInt32.fromProto(proto.getInt32Val(), fingerprint);
+        }
+        if (proto.hasFloatVal()) {
+            return FixedFloat.fromProto(proto.getFloatVal(), fingerprint);
+        }
+        if (proto.hasBoolVal()) {
+            return FixedBool.fromProto(proto.getBoolVal(), fingerprint);
+        }
+        if (proto.hasColorVal()) {
+            return FixedColor.fromProto(proto.getColorVal(), fingerprint);
+        }
+        throw new IllegalStateException("Proto was not a recognised instance of DynamicDataValue");
     }
-  }
-
-  /**
-   * Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
-   * created using this method can't be added to any other wrapper.
-   */
-  @RestrictTo(Scope.LIBRARY_GROUP)
-  @NonNull
-  public static DynamicDataValue dynamicDataValueFromProto(
-      @NonNull DynamicDataProto.DynamicDataValue proto) {
-    return dynamicDataValueFromProto(proto, null);
-  }
-
-  /** Creates a new wrapper instance from the proto. */
-  @RestrictTo(Scope.LIBRARY_GROUP)
-  @NonNull
-  public static DynamicDataValue dynamicDataValueFromProto(
-          @NonNull DynamicDataProto.DynamicDataValue proto, @Nullable Fingerprint fingerprint) {
-    if (proto.hasStringVal()) {
-      return FixedString.fromProto(proto.getStringVal(), fingerprint);
-    }
-    if (proto.hasInt32Val()) {
-      return FixedInt32.fromProto(proto.getInt32Val(), fingerprint);
-    }
-    if (proto.hasFloatVal()) {
-      return FixedFloat.fromProto(proto.getFloatVal(), fingerprint);
-    }
-    if (proto.hasBoolVal()) {
-      return FixedBool.fromProto(proto.getBoolVal(), fingerprint);
-    }
-    if (proto.hasColorVal()) {
-      return FixedColor.fromProto(proto.getColorVal(), fingerprint);
-    }
-    throw new IllegalStateException("Proto was not a recognised instance of DynamicDataValue");
-  }
-
 }
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
index 3718124..b490276 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/FixedValueBuilders.java
@@ -17,610 +17,619 @@
 package androidx.wear.protolayout.expression;
 
 import android.annotation.SuppressLint;
+
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
+import androidx.wear.protolayout.expression.proto.DynamicDataProto;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
 import androidx.wear.protolayout.expression.proto.FixedProto;
-import androidx.wear.protolayout.expression.proto.DynamicDataProto;
 
 /**
  * Builders for fixed value primitive types that can be used in dynamic expressions and in for state
  * state values.
  */
 final class FixedValueBuilders {
-  private FixedValueBuilders() {}
-
-  /**
-   * A fixed int32 type.
-   *
-   * @since 1.2
-   */
-  static final class FixedInt32
-      implements DynamicBuilders.DynamicInt32, DynamicDataBuilders.DynamicDataValue {
-    private final FixedProto.FixedInt32 mImpl;
-    @Nullable private final Fingerprint mFingerprint;
-
-    FixedInt32(FixedProto.FixedInt32 impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
-    }
+    private FixedValueBuilders() {}
 
     /**
-     * Gets the value.
+     * A fixed int32 type.
      *
      * @since 1.2
      */
-    public int getValue() {
-      return mImpl.getValue();
-    }
+    static final class FixedInt32
+            implements DynamicBuilders.DynamicInt32,
+                    DynamicDataBuilders.DynamicDataValue<DynamicBuilders.DynamicInt32> {
+        private final FixedProto.FixedInt32 mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedInt32(FixedProto.FixedInt32 impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedInt32 fromProto(
-            @NonNull FixedProto.FixedInt32 proto, @Nullable Fingerprint fingerprint) {
-      return new FixedInt32(proto, fingerprint);
-    }
+        /**
+         * Gets the value.
+         *
+         * @since 1.2
+         */
+        public int getValue() {
+            return mImpl.getValue();
+        }
 
-    @NonNull
-    static FixedInt32 fromProto(@NonNull FixedProto.FixedInt32 proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedInt32 toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedInt32 fromProto(
+                @NonNull FixedProto.FixedInt32 proto, @Nullable Fingerprint fingerprint) {
+            return new FixedInt32(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
-      return DynamicProto.DynamicInt32.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedInt32 fromProto(@NonNull FixedProto.FixedInt32 proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
-      return DynamicDataProto.DynamicDataValue.newBuilder().setInt32Val(mImpl).build();
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedInt32 toProto() {
+            return mImpl;
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedInt32{" + "value=" + getValue() + "}";
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
+            return DynamicProto.DynamicInt32.newBuilder().setFixed(mImpl).build();
+        }
 
-    /** Builder for {@link FixedInt32}. */
-    public static final class Builder
-        implements DynamicBuilders.DynamicInt32.Builder,
-            DynamicDataBuilders.DynamicDataValue.Builder {
-      private final FixedProto.FixedInt32.Builder mImpl = FixedProto.FixedInt32.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(974881783);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
+            return DynamicDataProto.DynamicDataValue.newBuilder().setInt32Val(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedInt32{" + "value=" + getValue() + "}";
+        }
 
-      /**
-       * Sets the value.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setValue(int value) {
-        mImpl.setValue(value);
-        mFingerprint.recordPropertyUpdate(1, value);
-        return this;
-      }
+        /** Builder for {@link FixedInt32}. */
+        public static final class Builder
+                implements DynamicBuilders.DynamicInt32.Builder,
+                        DynamicDataBuilders.DynamicDataValue.Builder<DynamicBuilders.DynamicInt32> {
+            private final FixedProto.FixedInt32.Builder mImpl = FixedProto.FixedInt32.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(974881783);
 
-      @Override
-      @NonNull
-      public FixedInt32 build() {
-        return new FixedInt32(mImpl.build(), mFingerprint);
-      }
-    }
-  }
+            public Builder() {}
 
-  /**
-   * A fixed string type.
-   *
-   * @since 1.2
-   */
-  static final class FixedString
-      implements DynamicBuilders.DynamicString, DynamicDataBuilders.DynamicDataValue {
-    private final FixedProto.FixedString mImpl;
-    @Nullable private final Fingerprint mFingerprint;
+            /**
+             * Sets the value.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setValue(int value) {
+                mImpl.setValue(value);
+                mFingerprint.recordPropertyUpdate(1, value);
+                return this;
+            }
 
-    FixedString(FixedProto.FixedString impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
+            @Override
+            @NonNull
+            public FixedInt32 build() {
+                return new FixedInt32(mImpl.build(), mFingerprint);
+            }
+        }
     }
 
     /**
-     * Gets the value.
+     * A fixed string type.
      *
      * @since 1.2
      */
-    @NonNull
-    public String getValue() {
-      return mImpl.getValue();
-    }
+    static final class FixedString
+            implements DynamicBuilders.DynamicString,
+                    DynamicDataBuilders.DynamicDataValue<DynamicBuilders.DynamicString> {
+        private final FixedProto.FixedString mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedString(FixedProto.FixedString impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedString fromProto(
-            @NonNull FixedProto.FixedString proto, @Nullable Fingerprint fingerprint) {
-      return new FixedString(proto, fingerprint);
-    }
+        /**
+         * Gets the value.
+         *
+         * @since 1.2
+         */
+        @NonNull
+        public String getValue() {
+            return mImpl.getValue();
+        }
 
-    @NonNull
-    static FixedString fromProto(@NonNull FixedProto.FixedString proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedString toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedString fromProto(
+                @NonNull FixedProto.FixedString proto, @Nullable Fingerprint fingerprint) {
+            return new FixedString(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicString toDynamicStringProto() {
-      return DynamicProto.DynamicString.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedString fromProto(@NonNull FixedProto.FixedString proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
-      return DynamicDataProto.DynamicDataValue.newBuilder().setStringVal(mImpl).build();
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedString toProto() {
+            return mImpl;
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedString{" + "value=" + getValue() + "}";
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicString toDynamicStringProto() {
+            return DynamicProto.DynamicString.newBuilder().setFixed(mImpl).build();
+        }
 
-    /** Builder for {@link FixedString}. */
-    public static final class Builder
-        implements DynamicBuilders.DynamicString.Builder,
-            DynamicDataBuilders.DynamicDataValue.Builder {
-      private final FixedProto.FixedString.Builder mImpl = FixedProto.FixedString.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(1963352072);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
+            return DynamicDataProto.DynamicDataValue.newBuilder().setStringVal(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedString{" + "value=" + getValue() + "}";
+        }
 
-      /**
-       * Sets the value.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setValue(@NonNull String value) {
-        mImpl.setValue(value);
-        mFingerprint.recordPropertyUpdate(1, value.hashCode());
-        return this;
-      }
+        /** Builder for {@link FixedString}. */
+        public static final class Builder
+                implements DynamicBuilders.DynamicString.Builder,
+                        DynamicDataBuilders.DynamicDataValue.Builder<
+                                DynamicBuilders.DynamicString> {
+            private final FixedProto.FixedString.Builder mImpl =
+                    FixedProto.FixedString.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(1963352072);
 
-      @Override
-      @NonNull
-      public FixedString build() {
-        return new FixedString(mImpl.build(), mFingerprint);
-      }
-    }
-  }
+            public Builder() {}
 
-  /**
-   * A fixed float type.
-   *
-   * @since 1.2
-   */
-  static final class FixedFloat
-      implements DynamicBuilders.DynamicFloat, DynamicDataBuilders.DynamicDataValue {
-    private final FixedProto.FixedFloat mImpl;
-    @Nullable private final Fingerprint mFingerprint;
+            /**
+             * Sets the value.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setValue(@NonNull String value) {
+                mImpl.setValue(value);
+                mFingerprint.recordPropertyUpdate(1, value.hashCode());
+                return this;
+            }
 
-    FixedFloat(FixedProto.FixedFloat impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
+            @Override
+            @NonNull
+            public FixedString build() {
+                return new FixedString(mImpl.build(), mFingerprint);
+            }
+        }
     }
 
     /**
-     * Gets the value. Note that a NaN value is considered invalid and any expression with this node
-     * will have an invalid value delivered via {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
+     * A fixed float type.
      *
      * @since 1.2
      */
-    public float getValue() {
-      return mImpl.getValue();
-    }
+    static final class FixedFloat
+            implements DynamicBuilders.DynamicFloat,
+                    DynamicDataBuilders.DynamicDataValue<DynamicBuilders.DynamicFloat> {
+        private final FixedProto.FixedFloat mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedFloat(FixedProto.FixedFloat impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedFloat fromProto(
-            @NonNull FixedProto.FixedFloat proto, @Nullable Fingerprint fingerprint) {
-      return new FixedFloat(proto, fingerprint);
-    }
+        /**
+         * Gets the value. Note that a NaN value is considered invalid and any expression with this
+         * node will have an invalid value delivered via {@link
+         * DynamicTypeValueReceiver<T>#onInvalidate()}.
+         *
+         * @since 1.2
+         */
+        public float getValue() {
+            return mImpl.getValue();
+        }
 
-    @NonNull
-    static FixedFloat fromProto(@NonNull FixedProto.FixedFloat proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedFloat toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedFloat fromProto(
+                @NonNull FixedProto.FixedFloat proto, @Nullable Fingerprint fingerprint) {
+            return new FixedFloat(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicFloat toDynamicFloatProto() {
-      return DynamicProto.DynamicFloat.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedFloat fromProto(@NonNull FixedProto.FixedFloat proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
-      return DynamicDataProto.DynamicDataValue.newBuilder().setFloatVal(mImpl).build();
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedFloat toProto() {
+            return mImpl;
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedFloat{" + "value=" + getValue() + "}";
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicFloat toDynamicFloatProto() {
+            return DynamicProto.DynamicFloat.newBuilder().setFixed(mImpl).build();
+        }
 
-    /** Builder for {@link FixedFloat}. */
-    public static final class Builder
-        implements DynamicBuilders.DynamicFloat.Builder,
-            DynamicDataBuilders.DynamicDataValue.Builder {
-      private final FixedProto.FixedFloat.Builder mImpl = FixedProto.FixedFloat.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(-144724541);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
+            return DynamicDataProto.DynamicDataValue.newBuilder().setFloatVal(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedFloat{" + "value=" + getValue() + "}";
+        }
 
+        /** Builder for {@link FixedFloat}. */
+        public static final class Builder
+                implements DynamicBuilders.DynamicFloat.Builder,
+                        DynamicDataBuilders.DynamicDataValue.Builder<DynamicBuilders.DynamicFloat> {
+            private final FixedProto.FixedFloat.Builder mImpl = FixedProto.FixedFloat.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-144724541);
 
-      /**
-       * Sets the value. Note that a NaN value is considered invalid and any expression with this
-       * node will have an invalid value delivered via
-       * {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setValue(float value) {
-        mImpl.setValue(value);
-        mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
-        return this;
-      }
+            public Builder() {}
 
-      @Override
-      @NonNull
-      public FixedFloat build() {
-        return new FixedFloat(mImpl.build(), mFingerprint);
-      }
-    }
-  }
+            /**
+             * Sets the value. Note that a NaN value is considered invalid and any expression with
+             * this node will have an invalid value delivered via {@link
+             * DynamicTypeValueReceiver<T>#onInvalidate()}.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setValue(float value) {
+                mImpl.setValue(value);
+                mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(value));
+                return this;
+            }
 
-  /**
-   * A fixed boolean type.
-   *
-   * @since 1.2
-   */
-  static final class FixedBool
-      implements DynamicBuilders.DynamicBool, DynamicDataBuilders.DynamicDataValue {
-    private final FixedProto.FixedBool mImpl;
-    @Nullable private final Fingerprint mFingerprint;
-
-    FixedBool(FixedProto.FixedBool impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
+            @Override
+            @NonNull
+            public FixedFloat build() {
+                return new FixedFloat(mImpl.build(), mFingerprint);
+            }
+        }
     }
 
     /**
-     * Gets the value.
+     * A fixed boolean type.
      *
      * @since 1.2
      */
-    public boolean getValue() {
-      return mImpl.getValue();
-    }
+    static final class FixedBool
+            implements DynamicBuilders.DynamicBool,
+                    DynamicDataBuilders.DynamicDataValue<DynamicBuilders.DynamicBool> {
+        private final FixedProto.FixedBool mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedBool(FixedProto.FixedBool impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedBool fromProto(
-            @NonNull FixedProto.FixedBool proto, @Nullable Fingerprint fingerprint) {
-      return new FixedBool(proto, fingerprint);
-    }
+        /**
+         * Gets the value.
+         *
+         * @since 1.2
+         */
+        public boolean getValue() {
+            return mImpl.getValue();
+        }
 
-    @NonNull
-    static FixedBool fromProto(@NonNull FixedProto.FixedBool proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedBool toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedBool fromProto(
+                @NonNull FixedProto.FixedBool proto, @Nullable Fingerprint fingerprint) {
+            return new FixedBool(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicBool toDynamicBoolProto() {
-      return DynamicProto.DynamicBool.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedBool fromProto(@NonNull FixedProto.FixedBool proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
-      return DynamicDataProto.DynamicDataValue.newBuilder().setBoolVal(mImpl).build();
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedBool toProto() {
+            return mImpl;
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedBool{" + "value=" + getValue() + "}";
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicBool toDynamicBoolProto() {
+            return DynamicProto.DynamicBool.newBuilder().setFixed(mImpl).build();
+        }
 
-    /** Builder for {@link FixedBool}. */
-    public static final class Builder
-        implements DynamicBuilders.DynamicBool.Builder,
-            DynamicDataBuilders.DynamicDataValue.Builder {
-      private final FixedProto.FixedBool.Builder mImpl = FixedProto.FixedBool.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(-665116398);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
+            return DynamicDataProto.DynamicDataValue.newBuilder().setBoolVal(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedBool{" + "value=" + getValue() + "}";
+        }
 
-      /**
-       * Sets the value.
-       *
-       * @since 1.2
-       */
-      @SuppressLint("MissingGetterMatchingBuilder")
-      @NonNull
-      public Builder setValue(boolean value) {
-        mImpl.setValue(value);
-        mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
-        return this;
-      }
+        /** Builder for {@link FixedBool}. */
+        public static final class Builder
+                implements DynamicBuilders.DynamicBool.Builder,
+                        DynamicDataBuilders.DynamicDataValue.Builder<DynamicBuilders.DynamicBool> {
+            private final FixedProto.FixedBool.Builder mImpl = FixedProto.FixedBool.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-665116398);
 
-      @Override
-      @NonNull
-      public FixedBool build() {
-        return new FixedBool(mImpl.build(), mFingerprint);
-      }
-    }
-  }
+            public Builder() {}
 
-  /**
-   * A fixed color type.
-   *
-   * @since 1.2
-   */
-  static final class FixedColor
-      implements DynamicBuilders.DynamicColor, DynamicDataBuilders.DynamicDataValue {
-    private final FixedProto.FixedColor mImpl;
-    @Nullable private final Fingerprint mFingerprint;
+            /**
+             * Sets the value.
+             *
+             * @since 1.2
+             */
+            @SuppressLint("MissingGetterMatchingBuilder")
+            @NonNull
+            public Builder setValue(boolean value) {
+                mImpl.setValue(value);
+                mFingerprint.recordPropertyUpdate(1, Boolean.hashCode(value));
+                return this;
+            }
 
-    FixedColor(FixedProto.FixedColor impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
+            @Override
+            @NonNull
+            public FixedBool build() {
+                return new FixedBool(mImpl.build(), mFingerprint);
+            }
+        }
     }
 
     /**
-     * Gets the color value, in ARGB format.
+     * A fixed color type.
      *
      * @since 1.2
      */
-    @ColorInt
-    public int getArgb() {
-      return mImpl.getArgb();
-    }
+    static final class FixedColor
+            implements DynamicBuilders.DynamicColor,
+                    DynamicDataBuilders.DynamicDataValue<DynamicBuilders.DynamicColor> {
+        private final FixedProto.FixedColor mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedColor(FixedProto.FixedColor impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedColor fromProto(
-            @NonNull FixedProto.FixedColor proto, @Nullable Fingerprint fingerprint) {
-      return new FixedColor(proto, fingerprint);
-    }
+        /**
+         * Gets the color value, in ARGB format.
+         *
+         * @since 1.2
+         */
+        @ColorInt
+        public int getArgb() {
+            return mImpl.getArgb();
+        }
 
-    @NonNull
-    static FixedColor fromProto(@NonNull FixedProto.FixedColor proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedColor toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedColor fromProto(
+                @NonNull FixedProto.FixedColor proto, @Nullable Fingerprint fingerprint) {
+            return new FixedColor(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicColor toDynamicColorProto() {
-      return DynamicProto.DynamicColor.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedColor fromProto(@NonNull FixedProto.FixedColor proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
-      return DynamicDataProto.DynamicDataValue.newBuilder().setColorVal(mImpl).build();
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedColor toProto() {
+            return mImpl;
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedColor{" + "argb=" + getArgb() + "}";
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicColor toDynamicColorProto() {
+            return DynamicProto.DynamicColor.newBuilder().setFixed(mImpl).build();
+        }
 
-    /** Builder for {@link FixedColor}. */
-    public static final class Builder
-        implements DynamicBuilders.DynamicColor.Builder,
-            DynamicDataBuilders.DynamicDataValue.Builder {
-      private final FixedProto.FixedColor.Builder mImpl = FixedProto.FixedColor.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(-1895809356);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicDataProto.DynamicDataValue toDynamicDataValueProto() {
+            return DynamicDataProto.DynamicDataValue.newBuilder().setColorVal(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedColor{" + "argb=" + getArgb() + "}";
+        }
 
-      /**
-       * Sets the color value, in ARGB format.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setArgb(@ColorInt int argb) {
-        mImpl.setArgb(argb);
-        mFingerprint.recordPropertyUpdate(1, argb);
-        return this;
-      }
+        /** Builder for {@link FixedColor}. */
+        public static final class Builder
+                implements DynamicBuilders.DynamicColor.Builder,
+                        DynamicDataBuilders.DynamicDataValue.Builder<DynamicBuilders.DynamicColor> {
+            private final FixedProto.FixedColor.Builder mImpl = FixedProto.FixedColor.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-1895809356);
 
-      @Override
-      @NonNull
-      public FixedColor build() {
-        return new FixedColor(mImpl.build(), mFingerprint);
-      }
-    }
-  }
+            public Builder() {}
 
-  /**
-   * A fixed time instant type.
-   *
-   * @since 1.2
-   */
-  static final class FixedInstant implements DynamicBuilders.DynamicInstant {
-    private final FixedProto.FixedInstant mImpl;
-    @Nullable private final Fingerprint mFingerprint;
+            /**
+             * Sets the color value, in ARGB format.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setArgb(@ColorInt int argb) {
+                mImpl.setArgb(argb);
+                mFingerprint.recordPropertyUpdate(1, argb);
+                return this;
+            }
 
-    FixedInstant(FixedProto.FixedInstant impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
+            @Override
+            @NonNull
+            public FixedColor build() {
+                return new FixedColor(mImpl.build(), mFingerprint);
+            }
+        }
     }
 
     /**
-     * Gets the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
+     * A fixed time instant type.
      *
      * @since 1.2
      */
-    public long getEpochSeconds() {
-      return mImpl.getEpochSeconds();
-    }
+    static final class FixedInstant implements DynamicBuilders.DynamicInstant {
+        private final FixedProto.FixedInstant mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
+        FixedInstant(FixedProto.FixedInstant impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
+        }
 
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static FixedInstant fromProto(
-            @NonNull FixedProto.FixedInstant proto, @Nullable Fingerprint fingerprint) {
-      return new FixedInstant(proto, fingerprint);
-    }
+        /**
+         * Gets the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
+         *
+         * @since 1.2
+         */
+        public long getEpochSeconds() {
+            return mImpl.getEpochSeconds();
+        }
 
-    @NonNull
-    static FixedInstant fromProto(@NonNull FixedProto.FixedInstant proto) {
-      return fromProto(proto, null);
-    }
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
 
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    FixedProto.FixedInstant toProto() {
-      return mImpl;
-    }
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static FixedInstant fromProto(
+                @NonNull FixedProto.FixedInstant proto, @Nullable Fingerprint fingerprint) {
+            return new FixedInstant(proto, fingerprint);
+        }
 
-    @Override
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public DynamicProto.DynamicInstant toDynamicInstantProto() {
-      return DynamicProto.DynamicInstant.newBuilder().setFixed(mImpl).build();
-    }
+        @NonNull
+        static FixedInstant fromProto(@NonNull FixedProto.FixedInstant proto) {
+            return fromProto(proto, null);
+        }
 
-    @Override
-    @NonNull
-    public String toString() {
-      return "FixedInstant{" + "epochSeconds=" + getEpochSeconds() + "}";
-    }
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        FixedProto.FixedInstant toProto() {
+            return mImpl;
+        }
 
-    /** Builder for {@link FixedInstant}. */
-    public static final class Builder implements DynamicBuilders.DynamicInstant.Builder {
-      private final FixedProto.FixedInstant.Builder mImpl = FixedProto.FixedInstant.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(-1986552556);
+        @Override
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public DynamicProto.DynamicInstant toDynamicInstantProto() {
+            return DynamicProto.DynamicInstant.newBuilder().setFixed(mImpl).build();
+        }
 
-      public Builder() {}
+        @Override
+        @NonNull
+        public String toString() {
+            return "FixedInstant{" + "epochSeconds=" + getEpochSeconds() + "}";
+        }
 
-      /**
-       * Sets the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
-       *
-       * @since 1.2
-       */
-      @NonNull
-      public Builder setEpochSeconds(long epochSeconds) {
-        mImpl.setEpochSeconds(epochSeconds);
-        mFingerprint.recordPropertyUpdate(1, Long.hashCode(epochSeconds));
-        return this;
-      }
+        /** Builder for {@link FixedInstant}. */
+        public static final class Builder implements DynamicBuilders.DynamicInstant.Builder {
+            private final FixedProto.FixedInstant.Builder mImpl =
+                    FixedProto.FixedInstant.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-1986552556);
+
+            public Builder() {}
+
+            /**
+             * Sets the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970.
+             *
+             * @since 1.2
+             */
+            @NonNull
+            public Builder setEpochSeconds(long epochSeconds) {
+                mImpl.setEpochSeconds(epochSeconds);
+                mFingerprint.recordPropertyUpdate(1, Long.hashCode(epochSeconds));
+                return this;
+            }
 
             @Override
             @NonNull
@@ -637,8 +646,7 @@
      */
     static final class FixedDuration implements DynamicBuilders.DynamicDuration {
         private final FixedProto.FixedDuration mImpl;
-        @Nullable
-        private final Fingerprint mFingerprint;
+        @Nullable private final Fingerprint mFingerprint;
 
         FixedDuration(FixedProto.FixedDuration impl, @Nullable Fingerprint fingerprint) {
             this.mImpl = impl;
@@ -700,8 +708,7 @@
                     FixedProto.FixedDuration.newBuilder();
             private final Fingerprint mFingerprint = new Fingerprint(9029504);
 
-            public Builder() {
-            }
+            public Builder() {}
 
             /**
              * Sets duration in seconds.
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataValues.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataValues.java
new file mode 100644
index 0000000..18dbb6c
--- /dev/null
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformDataValues.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.protolayout.expression;
+
+import static java.util.Collections.unmodifiableMap;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
+import androidx.collection.ArrayMap;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicType;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
+
+import java.util.Map;
+
+/** Typed mapping of {@link PlatformDataKey} to {@link DynamicDataValue}. */
+public final class PlatformDataValues {
+    @NonNull final Map<PlatformDataKey<?>, DynamicDataValue<?>> data;
+
+    /** Builder for {@link PlatformDataValues}. */
+    public static final class Builder {
+        @NonNull final Map<PlatformDataKey<?>, DynamicDataValue<?>> data = new ArrayMap<>();
+
+        /** Puts a key/value pair. */
+        @NonNull
+        @SuppressWarnings("BuilderSetStyle") // Map-style builder, getter is generic get().
+        public <T extends DynamicType> Builder put(
+                @NonNull PlatformDataKey<T> key, @NonNull DynamicDataValue<T> value) {
+            data.put(key, value);
+            return this;
+        }
+
+        /**
+         * Puts all values from another {@link PlatformDataValues}.
+         *
+         * <p>Values not in {@code other} are not removed from this {@link Builder}.
+         */
+        @NonNull
+        @SuppressWarnings("BuilderSetStyle") // Map-style builder, getter is generic get().
+        @VisibleForTesting
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public Builder putAll(@NonNull PlatformDataValues other) {
+            data.putAll(other.data);
+            return this;
+        }
+
+        /** Builds the {@link PlatformDataValues}. */
+        @NonNull
+        public PlatformDataValues build() {
+            return new PlatformDataValues(unmodifiableMap(data));
+        }
+    }
+
+    /** Creates a {@link PlatformDataValues} from a single key/value pair. */
+    @NonNull
+    public static <T extends DynamicType> PlatformDataValues of(
+            @NonNull PlatformDataKey<T> key, @NonNull DynamicDataValue<T> value) {
+        return new PlatformDataValues(Map.of(key, value));
+    }
+
+    PlatformDataValues(@NonNull Map<PlatformDataKey<?>, DynamicDataValue<?>> data) {
+        this.data = data;
+    }
+
+    /** Returns the key-value mapping. */
+    @NonNull
+    public Map<PlatformDataKey<?>, DynamicDataValue<?>> getAll() {
+        return unmodifiableMap(data);
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return String.format("PlatformDataValues{%s}", data);
+    }
+}
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
index f47f4d4..b5f203e 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/PlatformHealthSources.java
@@ -21,6 +21,7 @@
 
 import android.Manifest;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresPermission;
@@ -31,44 +32,35 @@
 import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /** Dynamic types for platform health sources. */
 public class PlatformHealthSources {
-    /** Constants for platform health sources. */
-    public static class Constants {
-        private Constants(){}
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        HEART_RATE_ACCURACY_UNKNOWN,
+        HEART_RATE_ACCURACY_NO_CONTACT,
+        HEART_RATE_ACCURACY_UNRELIABLE,
+        HEART_RATE_ACCURACY_LOW,
+        HEART_RATE_ACCURACY_MEDIUM,
+        HEART_RATE_ACCURACY_HIGH,
+    })
+    public @interface HeartRateAccuracy {}
 
-        /** The accuracy is unknown. */
-        private static final int HEART_RATE_ACCURACY_UNKNOWN_VALUE = 0;
-        /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
-        private static final int HEART_RATE_ACCURACY_NO_CONTACT_VALUE = 1;
-        /** Heart rate data is currently too unreliable to be used. */
-        private static final int HEART_RATE_ACCURACY_UNRELIABLE_VALUE = 2;
-        /** Heart rate data is available but the accuracy is low. */
-        private static final int HEART_RATE_ACCURACY_LOW_VALUE = 3;
-        /** Heart rate data is available and the accuracy is medium. */
-        private static final int HEART_RATE_ACCURACY_MEDIUM_VALUE = 4;
-        /** Heart rate data is available with high accuracy. */
-        private static final int HEART_RATE_ACCURACY_HIGH_VALUE = 5;
-
-        /** The accuracy is unknown. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_UNKNOWN =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_UNKNOWN_VALUE);
-        /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_NO_CONTACT =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_NO_CONTACT_VALUE);
-        /** Heart rate data is currently too unreliable to be used. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_UNRELIABLE =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_UNRELIABLE_VALUE);
-        /** Heart rate data is available but the accuracy is low. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_LOW =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_LOW_VALUE);
-        /** Heart rate data is available and the accuracy is medium. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_MEDIUM =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_MEDIUM_VALUE);
-        /** Heart rate data is available with high accuracy. */
-        public static final DynamicDataValue HEART_RATE_ACCURACY_HIGH =
-                DynamicDataValue.fromInt(HEART_RATE_ACCURACY_HIGH_VALUE);
-    }
+    /** Heart rate accuracy is unknown. */
+    public static final int HEART_RATE_ACCURACY_UNKNOWN = 0;
+    /** Heart rate cannot be acquired because the sensor is not properly contacting skin. */
+    public static final int HEART_RATE_ACCURACY_NO_CONTACT = 1;
+    /** Heart rate data is currently too unreliable to be used. */
+    public static final int HEART_RATE_ACCURACY_UNRELIABLE = 2;
+    /** Heart rate data is available but the accuracy is low. */
+    public static final int HEART_RATE_ACCURACY_LOW = 3;
+    /** Heart rate data is available and the accuracy is medium. */
+    public static final int HEART_RATE_ACCURACY_MEDIUM = 4;
+    /** Heart rate data is available with high accuracy. */
+    public static final int HEART_RATE_ACCURACY_HIGH = 5;
 
     /** Data sources keys for platform health sources. */
     public static class Keys {
@@ -229,34 +221,20 @@
             this.mImpl = impl;
         }
 
-        private DynamicHeartRateAccuracy(int val) {
-            this(DynamicInt32.constant(val));
+        /** Creates a constant-valued {@link DynamicHeartRateAccuracy}. */
+        @NonNull
+        public static DynamicHeartRateAccuracy constant(@HeartRateAccuracy int val) {
+            return new DynamicHeartRateAccuracy(DynamicInt32.constant(val));
         }
 
-        /** The accuracy is unknown. */
+        /** Creates a value to be provided from a {@code PlatformDataProvider}. */
         @NonNull
-        public static final DynamicHeartRateAccuracy UNKNOWN =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_UNKNOWN_VALUE);
-        /** The heart rate cannot be acquired because the sensor is not properly contacting skin. */
-        @NonNull
-        public static final DynamicHeartRateAccuracy NO_CONTACT =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_NO_CONTACT_VALUE);
-        /** Heart rate data is currently too unreliable to be used. */
-        @NonNull
-        public static final DynamicHeartRateAccuracy UNRELIABLE =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_UNRELIABLE_VALUE);
-        /** Heart rate data is available but the accuracy is low. */
-        @NonNull
-        public static final DynamicHeartRateAccuracy LOW =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_LOW_VALUE);
-        /** Heart rate data is available and the accuracy is medium. */
-        @NonNull
-        public static final DynamicHeartRateAccuracy MEDIUM =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_MEDIUM_VALUE);
-        /** Heart rate data is available with high accuracy. */
-        @NonNull
-        public static final DynamicHeartRateAccuracy HIGH =
-                new DynamicHeartRateAccuracy(Constants.HEART_RATE_ACCURACY_HIGH_VALUE);
+        @SuppressWarnings("unchecked") // DynamicHeartRateAccuracy acts like DynamicInt32.
+        public static DynamicDataValue<DynamicHeartRateAccuracy> dynamicDataValueOf(
+                @HeartRateAccuracy int val) {
+            return (DynamicDataValue<DynamicHeartRateAccuracy>)
+                    (DynamicDataValue<?>) DynamicDataValue.fromInt(val);
+        }
 
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicDataValueTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicDataValueTest.java
index 47237c4..fc97dc1 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicDataValueTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicDataValueTest.java
@@ -18,6 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicColor;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
 import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -27,14 +32,14 @@
 public final class DynamicDataValueTest {
   @Test
   public void boolDynamicDataValue() {
-    DynamicDataValue boolDynamicDataValue = DynamicDataValue.fromBool(true);
+    DynamicDataValue<DynamicBool> boolDynamicDataValue = DynamicDataValue.fromBool(true);
 
     assertThat(boolDynamicDataValue.toDynamicDataValueProto().getBoolVal().getValue()).isTrue();
   }
 
   @Test
   public void colorDynamicDataValue() {
-    DynamicDataValue colorDynamicDataValue = DynamicDataValue.fromColor(0xff00ff00);
+    DynamicDataValue<DynamicColor> colorDynamicDataValue = DynamicDataValue.fromColor(0xff00ff00);
 
     assertThat(colorDynamicDataValue.toDynamicDataValueProto().getColorVal().getArgb())
         .isEqualTo(0xff00ff00);
@@ -42,7 +47,7 @@
 
   @Test
   public void floatDynamicDataValue() {
-    DynamicDataValue floatDynamicDataValue = DynamicDataValue.fromFloat(42.42f);
+    DynamicDataValue<DynamicFloat> floatDynamicDataValue = DynamicDataValue.fromFloat(42.42f);
 
     assertThat(floatDynamicDataValue.toDynamicDataValueProto().getFloatVal().getValue())
         .isWithin(0.0001f)
@@ -51,7 +56,7 @@
 
   @Test
   public void intDynamicDataValue() {
-    DynamicDataValue intDynamicDataValue = DynamicDataValue.fromInt(42);
+    DynamicDataValue<DynamicInt32> intDynamicDataValue = DynamicDataValue.fromInt(42);
 
     assertThat(intDynamicDataValue.toDynamicDataValueProto().getInt32Val().getValue())
             .isEqualTo(42);
@@ -59,7 +64,8 @@
 
   @Test
   public void stringDynamicDataValue() {
-    DynamicDataValue stringDynamicDataValue = DynamicDataValue.fromString("constant-value");
+    DynamicDataValue<DynamicString> stringDynamicDataValue =
+            DynamicDataValue.fromString("constant-value");
 
     assertThat(stringDynamicDataValue.toDynamicDataValueProto().getStringVal().getValue())
         .isEqualTo("constant-value");
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/color.proto b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
index d19205a..60725d1 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/color.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/color.proto
@@ -10,11 +10,14 @@
 
 // A property defining a color.
 message ColorProp {
-  // The static color value, in ARGB format. If a dynamic value is also set and the
-  // renderer supports dynamic values for the corresponding field, this static
-  // value will be ignored. If the static value is not specified, zero
-  // (equivalent to {@link Color#TRANSPARENT}) will be used instead.
-  optional uint32 argb = 1;
+
+  oneof optional_argb {
+    // The static color value, in ARGB format. If a dynamic value is also set and the
+    // renderer supports dynamic values for the corresponding field, this static
+    // value will be ignored. If the static value is not specified, zero
+    // (equivalent to {@link Color#TRANSPARENT}) will be used instead.
+    uint32 argb = 1;
+  }
 
   // The dynamic value. Note that when setting this value, the static value is
   // still required to be set to support older renderers that only read the
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto b/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
index 5ff8223..dc79936 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/dimension.proto
@@ -12,10 +12,13 @@
 
 // A type for linear dimensions, measured in dp.
 message DpProp {
-  // The static value, in dp. If a dynamic value is also set and the renderer supports
-  // dynamic values for the corresponding field, this static value will be
-  // ignored. If the static value is not specified, zero will be used instead.
-  optional float value = 1;
+
+  oneof optional_value {
+    // The static value, in dp. If a dynamic value is also set and the renderer supports
+    // dynamic values for the corresponding field, this static value will be
+    // ignored. If the static value is not specified, zero will be used instead.
+    float value = 1;
+  }
 
   // The dynamic value, in dp. Note that when setting this value, the static value is
   // still required to be set to support older renderers that only read the
@@ -82,10 +85,13 @@
 
 // A type for angular dimensions, measured in degrees.
 message DegreesProp {
-  // The static value, in degrees. If a dynamic value is also set and the renderer
-  // supports dynamic values for the corresponding field, this static value will be
-  // ignored. If the static value is not specified, zero will be used instead.
-  optional float value = 1;
+
+  oneof optional_value {
+    // The static value, in degrees. If a dynamic value is also set and the renderer
+    // supports dynamic values for the corresponding field, this static value will be
+    // ignored. If the static value is not specified, zero will be used instead.
+    float value = 1;
+  }
 
   // The dynamic value, in degrees. Note that when setting this value, the static value is
   // still required to be set to support older renderers that only read the
@@ -162,7 +168,7 @@
 
 // A dimension that can be applied to a ExtensionLayoutElement element.
 message ExtensionDimension {
-      oneof inner {
+  oneof inner {
     DpProp linear_dimension = 1;
   }
 }
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/types.proto b/wear/protolayout/protolayout-proto/src/main/proto/types.proto
index e5d68f0..059ec86 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/types.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/types.proto
@@ -51,10 +51,13 @@
 
 // A float type.
 message FloatProp {
-  // The static value. If a dynamic value is also set and the renderer supports
-  // dynamic values for the corresponding field, this static value will be
-  // ignored. If the static value is not specified, zero will be used instead.
-  optional float value = 1;
+
+  oneof optional_value {
+    // The static value. If a dynamic value is also set and the renderer supports
+    // dynamic values for the corresponding field, this static value will be
+    // ignored. If the static value is not specified, zero will be used instead.
+    float value = 1;
+  }
 
   // The dynamic value. Note that when setting this value, the static value is
   // still required to be set to support older renderers that only read the
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index b8c0903..1fd14e2 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -35,7 +35,7 @@
     implementation "androidx.concurrent:concurrent-futures:1.1.0"
     implementation("androidx.core:core:1.7.0")
     implementation("androidx.vectordrawable:vectordrawable-seekable:1.0.0-beta01")
-    implementation("androidx.wear:wear:1.3.0-alpha04")
+    implementation("androidx.wear:wear:1.3.0-beta01")
 
     testImplementation(libs.mockitoCore4)
     testImplementation(libs.testExtJunit)
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index cfb4842..4089bc7 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -1173,14 +1173,14 @@
   }
 
   public static final class StateBuilders.State {
-    method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getKeyToValueMapping();
+    method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!> getKeyToValueMapping();
     method public String getLastClickableId();
     method public static int getMaxStateEntryCount();
   }
 
   public static final class StateBuilders.State.Builder {
     ctor public StateBuilders.State.Builder();
-    method public androidx.wear.protolayout.StateBuilders.State.Builder addKeyToValueMapping(androidx.wear.protolayout.expression.AppDataKey<?>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue);
+    method public <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.StateBuilders.State.Builder addKeyToValueMapping(androidx.wear.protolayout.expression.AppDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
     method public androidx.wear.protolayout.StateBuilders.State build();
   }
 
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index cfb4842..4089bc7 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -1173,14 +1173,14 @@
   }
 
   public static final class StateBuilders.State {
-    method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!> getKeyToValueMapping();
+    method public java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!> getKeyToValueMapping();
     method public String getLastClickableId();
     method public static int getMaxStateEntryCount();
   }
 
   public static final class StateBuilders.State.Builder {
     ctor public StateBuilders.State.Builder();
-    method public androidx.wear.protolayout.StateBuilders.State.Builder addKeyToValueMapping(androidx.wear.protolayout.expression.AppDataKey<?>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue);
+    method public <T extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType> androidx.wear.protolayout.StateBuilders.State.Builder addKeyToValueMapping(androidx.wear.protolayout.expression.AppDataKey<T!>, androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<T!>);
     method public androidx.wear.protolayout.StateBuilders.State build();
   }
 
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
index 9740840..e68e65f 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/StateBuilders.java
@@ -19,16 +19,19 @@
 import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
 
 import android.annotation.SuppressLint;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
-import androidx.wear.protolayout.expression.DynamicDataBuilders;
-import androidx.wear.protolayout.expression.Fingerprint;
-import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 import androidx.wear.protolayout.expression.AppDataKey;
+import androidx.wear.protolayout.expression.DynamicBuilders.DynamicType;
+import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
+import androidx.wear.protolayout.expression.Fingerprint;
 import androidx.wear.protolayout.expression.proto.DynamicDataProto;
 import androidx.wear.protolayout.proto.StateProto;
+
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -36,156 +39,154 @@
 
 /** Builders for state of a layout. */
 public final class StateBuilders {
-  private StateBuilders() {}
-
-  /**
-   * {@link State} information.
-   *
-   * @since 1.0
-   */
-  public static final class State {
-    private final StateProto.State mImpl;
-    @Nullable private final Fingerprint mFingerprint;
-
-    private static final int MAX_STATE_ENTRY_COUNT = 30;
-
-    State(StateProto.State impl, @Nullable Fingerprint fingerprint) {
-      this.mImpl = impl;
-      this.mFingerprint = fingerprint;
-    }
-
+    private StateBuilders() {}
 
     /**
-     * Returns the maximum number for state entries that can be added to the {@link State} using
-     * {@link Builder#addKeyToValueMapping(AppDataKey, DynamicDataValue)}.
-     *
-     * <p>The ProtoLayout state model is not designed to handle large volumes of layout provided
-     * state. So we limit the number of state entries to keep the on-the-wire size and state
-     * store update times manageable.
-     */
-    static public int getMaxStateEntryCount(){
-      return MAX_STATE_ENTRY_COUNT;
-    }
-    /**
-     * Gets the ID of the clickable that was last clicked.
+     * {@link State} information.
      *
      * @since 1.0
      */
-    @NonNull
-    public String getLastClickableId() {
-      return mImpl.getLastClickableId();
-    }
+    public static final class State {
+        private final StateProto.State mImpl;
+        @Nullable private final Fingerprint mFingerprint;
 
-    /**
-     * Gets any shared state between the provider and renderer.
-     *
-     * @since 1.2
-     */
-    @NonNull
-    public Map<AppDataKey<?>, DynamicDataValue> getKeyToValueMapping() {
-      Map<AppDataKey<?>, DynamicDataValue> map = new HashMap<>();
-      for (Entry<String, DynamicDataProto.DynamicDataValue> entry :
-          mImpl.getIdToValueMap().entrySet()) {
-        map.put(
-                new AppDataKey<>(entry.getKey()),
-                DynamicDataBuilders.dynamicDataValueFromProto(entry.getValue()));
-      }
-      return Collections.unmodifiableMap(map);
-    }
+        private static final int MAX_STATE_ENTRY_COUNT = 30;
 
-    /**
-     * Get the fingerprint for this object, or null if unknown.
-     *
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public Fingerprint getFingerprint() {
-      return mFingerprint;
-    }
-
-    /** Creates a new wrapper instance from the proto. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static State fromProto(
-        @NonNull StateProto.State proto, @Nullable Fingerprint fingerprint) {
-      return new State(proto, fingerprint);
-    }
-
-    /**
-     * Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
-     * created using this method can't be added to any other wrapper.
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static State fromProto(@NonNull StateProto.State proto) {
-      return fromProto(proto, null);
-    }
-
-    /** Returns the internal proto instance. */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public StateProto.State toProto() {
-      return mImpl;
-    }
-
-    @Override
-    @NonNull
-    public String toString() {
-      return "State{"
-          + "lastClickableId="
-          + getLastClickableId()
-          + ", keyToValueMapping="
-          + getKeyToValueMapping()
-          + "}";
-    }
-
-    /** Builder for {@link State} */
-    public static final class Builder {
-      private final StateProto.State.Builder mImpl = StateProto.State.newBuilder();
-      private final Fingerprint mFingerprint = new Fingerprint(-688813584);
-
-      public Builder() {}
-
-      /**
-       * Adds an entry into any shared state between the provider and renderer.
-       *
-       * @throws IllegalStateException if adding the new key/value will make the state larger
-       * than the allowed limit ({@link #getMaxStateEntryCount()}).
-       * @since 1.2
-       */
-      @SuppressLint("MissingGetterMatchingBuilder")
-      @NonNull
-      public Builder addKeyToValueMapping(
-              @NonNull AppDataKey<?> sourceKey,
-              @NonNull DynamicDataValue value) {
-        if (mImpl.getIdToValueMap().size() >= getMaxStateEntryCount()) {
-          throw new IllegalStateException(
-                  String.format(
-                          "Can't add more entries to the state. It is already at its "
-                                  + "maximum allowed size of %d.", getMaxStateEntryCount()));
+        State(StateProto.State impl, @Nullable Fingerprint fingerprint) {
+            this.mImpl = impl;
+            this.mFingerprint = fingerprint;
         }
-        mImpl.putIdToValue(sourceKey.getKey(), value.toDynamicDataValueProto());
-        mFingerprint.recordPropertyUpdate(
-                sourceKey.getKey().hashCode(),
-                checkNotNull(value.getFingerprint()).aggregateValueAsInt());
-        return this;
-      }
 
-      /** Builds an instance from accumulated values.
-       *
-       * @throws IllegalStateException if number of key/value pairs are greater than
-       * {@link #getMaxStateEntryCount()}.
-       */
-      @NonNull
-      public State build() {
-        if (mImpl.getIdToValueMap().size() > getMaxStateEntryCount()) {
-          throw new IllegalStateException(
-                  String.format(
-                          "State size is too large: %d. Maximum " + "allowed state size is %d.",
-                          mImpl.getIdToValueMap().size(), getMaxStateEntryCount()));
+        /**
+         * Returns the maximum number for state entries that can be added to the {@link State} using
+         * {@link Builder#addKeyToValueMapping(AppDataKey, DynamicDataValue)}.
+         *
+         * <p>The ProtoLayout state model is not designed to handle large volumes of layout provided
+         * state. So we limit the number of state entries to keep the on-the-wire size and state
+         * store update times manageable.
+         */
+        public static int getMaxStateEntryCount() {
+            return MAX_STATE_ENTRY_COUNT;
         }
-        return new State(mImpl.build(), mFingerprint);
-      }
+        /**
+         * Gets the ID of the clickable that was last clicked.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public String getLastClickableId() {
+            return mImpl.getLastClickableId();
+        }
+
+        /**
+         * Gets any shared state between the provider and renderer.
+         *
+         * @since 1.2
+         */
+        @NonNull
+        public Map<AppDataKey<?>, DynamicDataValue<?>> getKeyToValueMapping() {
+            Map<AppDataKey<?>, DynamicDataValue<?>> map = new HashMap<>();
+            for (Entry<String, DynamicDataProto.DynamicDataValue> entry :
+                    mImpl.getIdToValueMap().entrySet()) {
+                map.put(
+                        new AppDataKey<>(entry.getKey()),
+                        DynamicDataBuilders.dynamicDataValueFromProto(entry.getValue()));
+            }
+            return Collections.unmodifiableMap(map);
+        }
+
+        /** Get the fingerprint for this object, or null if unknown. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Nullable
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
+        }
+
+        /** Creates a new wrapper instance from the proto. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static State fromProto(
+                @NonNull StateProto.State proto, @Nullable Fingerprint fingerprint) {
+            return new State(proto, fingerprint);
+        }
+
+        /**
+         * Creates a new wrapper instance from the proto. Intended for testing purposes only. An
+         * object created using this method can't be added to any other wrapper.
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static State fromProto(@NonNull StateProto.State proto) {
+            return fromProto(proto, null);
+        }
+
+        /** Returns the internal proto instance. */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public StateProto.State toProto() {
+            return mImpl;
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "State{"
+                    + "lastClickableId="
+                    + getLastClickableId()
+                    + ", keyToValueMapping="
+                    + getKeyToValueMapping()
+                    + "}";
+        }
+
+        /** Builder for {@link State} */
+        public static final class Builder {
+            private final StateProto.State.Builder mImpl = StateProto.State.newBuilder();
+            private final Fingerprint mFingerprint = new Fingerprint(-688813584);
+
+            public Builder() {}
+
+            /**
+             * Adds an entry into any shared state between the provider and renderer.
+             *
+             * @throws IllegalStateException if adding the new key/value will make the state larger
+             *     than the allowed limit ({@link #getMaxStateEntryCount()}).
+             * @since 1.2
+             */
+            @NonNull
+            @SuppressLint("MissingGetterMatchingBuilder")
+            public <T extends DynamicType> Builder addKeyToValueMapping(
+                    @NonNull AppDataKey<T> sourceKey, @NonNull DynamicDataValue<T> value) {
+                if (mImpl.getIdToValueMap().size() >= getMaxStateEntryCount()) {
+                    throw new IllegalStateException(
+                            String.format(
+                                    "Can't add more entries to the state. It is already at its "
+                                            + "maximum allowed size of %d.",
+                                    getMaxStateEntryCount()));
+                }
+                mImpl.putIdToValue(sourceKey.getKey(), value.toDynamicDataValueProto());
+                mFingerprint.recordPropertyUpdate(
+                        sourceKey.getKey().hashCode(),
+                        checkNotNull(value.getFingerprint()).aggregateValueAsInt());
+                return this;
+            }
+
+            /**
+             * Builds an instance from accumulated values.
+             *
+             * @throws IllegalStateException if number of key/value pairs are greater than {@link
+             *     #getMaxStateEntryCount()}.
+             */
+            @NonNull
+            public State build() {
+                if (mImpl.getIdToValueMap().size() > getMaxStateEntryCount()) {
+                    throw new IllegalStateException(
+                            String.format(
+                                    "State size is too large: %d. "
+                                            + "Maximum allowed state size is %d.",
+                                    mImpl.getIdToValueMap().size(), getMaxStateEntryCount()));
+                }
+                return new State(mImpl.build(), mFingerprint);
+            }
+        }
     }
-  }
 }
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
index 9acc657..a843a24 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/TypeBuilders.java
@@ -49,7 +49,7 @@
         }
 
         /**
-         * Gets the value.
+         * Gets the static value.
          *
          * @since 1.0
          */
@@ -101,7 +101,7 @@
             public Builder() {}
 
             /**
-             * Sets the value.
+             * Sets the static value.
              *
              * @since 1.0
              */
@@ -529,7 +529,7 @@
         }
 
         /**
-         * Gets the value.
+         * Gets the static value.
          *
          * @since 1.0
          */
@@ -581,7 +581,7 @@
             public Builder() {}
 
             /**
-             * Sets the value.
+             * Sets the static value.
              *
              * @since 1.0
              */
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
index 57bcb1e..7468113 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/StateBuildersTest.java
@@ -19,17 +19,12 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import androidx.wear.protolayout.expression.AppDataKey;
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicBool;
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
-import androidx.wear.protolayout.expression.DynamicDataBuilders;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
-import java.util.Map;
-import java.util.Set;
-
 @RunWith(RobolectricTestRunner.class)
 public class StateBuildersTest {
     @Test
@@ -41,22 +36,24 @@
 
     @Test
     public void additionalState() {
-        DynamicDataBuilders.DynamicDataValue boolValue =
-                DynamicDataBuilders.DynamicDataValue.fromBool(true);
-        DynamicDataBuilders.DynamicDataValue stringValue =
-                DynamicDataBuilders.DynamicDataValue.fromString("string");
         StateBuilders.State state =
                 new StateBuilders.State.Builder()
-                        .addKeyToValueMapping(new AppDataKey<DynamicBool>("boolValue"), boolValue)
                         .addKeyToValueMapping(
-                                new AppDataKey<DynamicString>("stringValue"), stringValue)
+                                new AppDataKey<>("boolValue"), DynamicDataValue.fromBool(true))
+                        .addKeyToValueMapping(
+                                new AppDataKey<>("stringValue"),
+                                DynamicDataValue.fromString("string"))
                         .build();
         assertThat(state.getKeyToValueMapping()).hasSize(2);
-        assertThat(state.getKeyToValueMapping().get(
-                new AppDataKey<>("boolValue")).toDynamicDataValueProto())
-                .isEqualTo(boolValue.toDynamicDataValueProto());
-        assertThat(state.getKeyToValueMapping().get(
-                new AppDataKey<>("stringValue")).toDynamicDataValueProto())
-                .isEqualTo(stringValue.toDynamicDataValueProto());
+        assertThat(
+                        state.getKeyToValueMapping()
+                                .get(new AppDataKey<>("boolValue"))
+                                .toDynamicDataValueProto())
+                .isEqualTo(DynamicDataValue.fromBool(true).toDynamicDataValueProto());
+        assertThat(
+                        state.getKeyToValueMapping()
+                                .get(new AppDataKey<>("stringValue"))
+                                .toDynamicDataValueProto())
+                .isEqualTo(DynamicDataValue.fromString("string").toDynamicDataValueProto());
     }
 }
diff --git a/wear/tiles/tiles-renderer/api/current.txt b/wear/tiles/tiles-renderer/api/current.txt
index 3bd3943..2d38960 100644
--- a/wear/tiles/tiles-renderer/api/current.txt
+++ b/wear/tiles/tiles-renderer/api/current.txt
@@ -48,7 +48,7 @@
     ctor public TileRenderer(android.content.Context, java.util.concurrent.Executor, java.util.function.Consumer<androidx.wear.protolayout.StateBuilders.State!>);
     method @Deprecated public android.view.View? inflate(android.view.ViewGroup);
     method public com.google.common.util.concurrent.ListenableFuture<android.view.View!> inflateAsync(androidx.wear.protolayout.LayoutElementBuilders.Layout, androidx.wear.protolayout.ResourceBuilders.Resources, android.view.ViewGroup);
-    method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
   }
 
   @Deprecated public static interface TileRenderer.LoadActionListener {
diff --git a/wear/tiles/tiles-renderer/api/restricted_current.txt b/wear/tiles/tiles-renderer/api/restricted_current.txt
index 3bd3943..2d38960 100644
--- a/wear/tiles/tiles-renderer/api/restricted_current.txt
+++ b/wear/tiles/tiles-renderer/api/restricted_current.txt
@@ -48,7 +48,7 @@
     ctor public TileRenderer(android.content.Context, java.util.concurrent.Executor, java.util.function.Consumer<androidx.wear.protolayout.StateBuilders.State!>);
     method @Deprecated public android.view.View? inflate(android.view.ViewGroup);
     method public com.google.common.util.concurrent.ListenableFuture<android.view.View!> inflateAsync(androidx.wear.protolayout.LayoutElementBuilders.Layout, androidx.wear.protolayout.ResourceBuilders.Resources, android.view.ViewGroup);
-    method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue!>);
+    method public void setState(java.util.Map<androidx.wear.protolayout.expression.AppDataKey<?>!,androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue<?>!>);
   }
 
   @Deprecated public static interface TileRenderer.LoadActionListener {
diff --git a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
index df588c4..82e1946 100644
--- a/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
+++ b/wear/tiles/tiles-renderer/src/main/java/androidx/wear/tiles/renderer/TileRenderer.java
@@ -241,7 +241,7 @@
      * @throws IllegalStateException if number of {@code newState} entries is greater than {@link
      *     StateStore#getMaxStateEntryCount()}.
      */
-    public void setState(@NonNull Map<AppDataKey<?>, DynamicDataValue> newState) {
+    public void setState(@NonNull Map<AppDataKey<?>, DynamicDataValue<?>> newState) {
         mStateStore.setAppStateEntryValues(newState);
     }
 
diff --git a/wear/tiles/tiles/src/test/java/androidx/wear/tiles/RequestBuildersTest.java b/wear/tiles/tiles/src/test/java/androidx/wear/tiles/RequestBuildersTest.java
index 93ea260..d769dba 100644
--- a/wear/tiles/tiles/src/test/java/androidx/wear/tiles/RequestBuildersTest.java
+++ b/wear/tiles/tiles/src/test/java/androidx/wear/tiles/RequestBuildersTest.java
@@ -22,11 +22,10 @@
 import androidx.wear.protolayout.DeviceParametersBuilders;
 import androidx.wear.protolayout.DeviceParametersBuilders.DeviceParameters;
 import androidx.wear.protolayout.StateBuilders.State;
-import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
-import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 import androidx.wear.protolayout.expression.AppDataKey;
-import androidx.wear.protolayout.expression.proto.FixedProto;
+import androidx.wear.protolayout.expression.DynamicDataBuilders.DynamicDataValue;
 import androidx.wear.protolayout.expression.proto.DynamicDataProto;
+import androidx.wear.protolayout.expression.proto.FixedProto;
 import androidx.wear.protolayout.proto.DeviceParametersProto;
 import androidx.wear.protolayout.proto.StateProto;
 import androidx.wear.tiles.RequestBuilders.ResourcesRequest;
@@ -48,7 +47,7 @@
                         .setCurrentState(
                                 new State.Builder()
                                         .addKeyToValueMapping(
-                                                new AppDataKey<DynamicInt32>("entry_id"),
+                                                new AppDataKey<>("entry_id"),
                                                 DynamicDataValue.fromInt(13))
                                         .build())
                         .setDeviceConfiguration(
diff --git a/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt
index 60bc532..ff02a33 100644
--- a/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt
+++ b/wear/watchface/watchface-complications-data-source-samples/src/main/java/androidx/wear/watchface/complications/datasource/samples/dynamic/HealthDataSourceServices.kt
@@ -22,6 +22,8 @@
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString
 import androidx.wear.protolayout.expression.PlatformHealthSources
 import androidx.wear.protolayout.expression.PlatformHealthSources.DynamicHeartRateAccuracy
+import androidx.wear.protolayout.expression.PlatformHealthSources.HEART_RATE_ACCURACY_MEDIUM
+import androidx.wear.protolayout.expression.PlatformHealthSources.heartRateAccuracy
 import androidx.wear.watchface.complications.data.ComplicationData
 import androidx.wear.watchface.complications.data.ComplicationType
 import androidx.wear.watchface.complications.data.DynamicComplicationText
@@ -83,8 +85,8 @@
             get() =
                 if (checkSelfPermission(permission.BODY_SENSORS) == PERMISSION_GRANTED) {
                     DynamicFloat.onCondition(
-                            PlatformHealthSources.heartRateAccuracy()
-                                .gte(DynamicHeartRateAccuracy.MEDIUM)
+                            heartRateAccuracy()
+                                .gte(DynamicHeartRateAccuracy.constant(HEART_RATE_ACCURACY_MEDIUM))
                         )
                         .use(PlatformHealthSources.heartRateBpm())
                         .elseUse(0f)
@@ -96,8 +98,8 @@
             get() {
                 require(checkSelfPermission(permission.BODY_SENSORS) == PERMISSION_GRANTED)
                 return DynamicString.onCondition(
-                        PlatformHealthSources.heartRateAccuracy()
-                            .gte(DynamicHeartRateAccuracy.MEDIUM)
+                        heartRateAccuracy()
+                            .gte(DynamicHeartRateAccuracy.constant(HEART_RATE_ACCURACY_MEDIUM))
                     )
                     .use(PlatformHealthSources.heartRateBpm().format())
                     .elseUse(getString(R.string.dynamic_data_low_accuracy))
diff --git a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
index ac5eec6..4b26610 100644
--- a/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
+++ b/wear/watchface/watchface-complications-data/src/test/java/androidx/wear/watchface/complications/data/ComplicationDataEvaluatorTest.kt
@@ -81,7 +81,7 @@
      */
     enum class DataWithExpressionScenario(
         val expressed: WireComplicationData,
-        val states: List<Map<AppDataKey<*>, DynamicDataValue>>,
+        val states: List<Map<AppDataKey<*>, DynamicDataValue<*>>>,
         val evaluated: List<WireComplicationData>,
     ) {
         SET_IMMEDIATELY_WHEN_ALL_DATA_AVAILABLE(
diff --git a/window/extensions/extensions/api/current.txt b/window/extensions/extensions/api/current.txt
index 20f4ee8..22888f8 100644
--- a/window/extensions/extensions/api/current.txt
+++ b/window/extensions/extensions/api/current.txt
@@ -53,11 +53,15 @@
   public interface ActivityEmbeddingComponent {
     method public void clearSplitAttributesCalculator();
     method public void clearSplitInfoCallback();
+    method public default void finishActivityStacks(java.util.Set<android.os.IBinder!>);
+    method public default void invalidateTopVisibleSplitAttributes();
     method public boolean isActivityEmbedded(android.app.Activity);
     method public void setEmbeddingRules(java.util.Set<androidx.window.extensions.embedding.EmbeddingRule!>);
+    method public default android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.os.IBinder);
     method public void setSplitAttributesCalculator(androidx.window.extensions.core.util.function.Function<androidx.window.extensions.embedding.SplitAttributesCalculatorParams!,androidx.window.extensions.embedding.SplitAttributes!>);
     method public default void setSplitInfoCallback(androidx.window.extensions.core.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
     method @Deprecated public void setSplitInfoCallback(java.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
+    method public default void updateSplitAttributes(android.os.IBinder, androidx.window.extensions.embedding.SplitAttributes);
   }
 
   public class ActivityRule extends androidx.window.extensions.embedding.EmbeddingRule {
@@ -135,6 +139,7 @@
     method public androidx.window.extensions.embedding.ActivityStack getSecondaryActivityStack();
     method public androidx.window.extensions.embedding.SplitAttributes getSplitAttributes();
     method @Deprecated public float getSplitRatio();
+    method public android.os.IBinder getToken();
   }
 
   public class SplitPairRule extends androidx.window.extensions.embedding.SplitRule {
diff --git a/window/extensions/extensions/api/restricted_current.txt b/window/extensions/extensions/api/restricted_current.txt
index 20f4ee8..22888f8 100644
--- a/window/extensions/extensions/api/restricted_current.txt
+++ b/window/extensions/extensions/api/restricted_current.txt
@@ -53,11 +53,15 @@
   public interface ActivityEmbeddingComponent {
     method public void clearSplitAttributesCalculator();
     method public void clearSplitInfoCallback();
+    method public default void finishActivityStacks(java.util.Set<android.os.IBinder!>);
+    method public default void invalidateTopVisibleSplitAttributes();
     method public boolean isActivityEmbedded(android.app.Activity);
     method public void setEmbeddingRules(java.util.Set<androidx.window.extensions.embedding.EmbeddingRule!>);
+    method public default android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.os.IBinder);
     method public void setSplitAttributesCalculator(androidx.window.extensions.core.util.function.Function<androidx.window.extensions.embedding.SplitAttributesCalculatorParams!,androidx.window.extensions.embedding.SplitAttributes!>);
     method public default void setSplitInfoCallback(androidx.window.extensions.core.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
     method @Deprecated public void setSplitInfoCallback(java.util.function.Consumer<java.util.List<androidx.window.extensions.embedding.SplitInfo!>!>);
+    method public default void updateSplitAttributes(android.os.IBinder, androidx.window.extensions.embedding.SplitAttributes);
   }
 
   public class ActivityRule extends androidx.window.extensions.embedding.EmbeddingRule {
@@ -135,6 +139,7 @@
     method public androidx.window.extensions.embedding.ActivityStack getSecondaryActivityStack();
     method public androidx.window.extensions.embedding.SplitAttributes getSplitAttributes();
     method @Deprecated public float getSplitRatio();
+    method public android.os.IBinder getToken();
   }
 
   public class SplitPairRule extends androidx.window.extensions.embedding.SplitRule {
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
index e34b0e5..d50e6b3 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
@@ -18,12 +18,20 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.app.ActivityOptions;
+import android.os.IBinder;
+
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.window.extensions.area.WindowAreaComponent;
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.ActivityStack;
+import androidx.window.extensions.embedding.SplitAttributes;
+import androidx.window.extensions.embedding.SplitInfo;
 import androidx.window.extensions.layout.WindowLayoutComponent;
 
+import java.util.Set;
+
 /**
  * A class to provide instances of different WindowManager Jetpack extension components. An OEM must
  * implement all the availability methods to state which WindowManager Jetpack extension
@@ -55,6 +63,7 @@
      *     <li>{@link androidx.window.extensions.layout.FoldingFeature} APIs</li>
      *     <li>{@link androidx.window.extensions.layout.WindowLayoutInfo} APIs</li>
      *     <li>{@link androidx.window.extensions.layout.WindowLayoutComponent} APIs</li>
+     *     <li>{@link androidx.window.extensions.area.WindowAreaComponent} APIs</li>
      * </ul>
      * </p>
      */
@@ -76,6 +85,27 @@
     @RestrictTo(LIBRARY_GROUP)
     int VENDOR_API_LEVEL_2 = 2;
 
+    // TODO(b/241323716) Removed after we have annotation to check API level
+    /**
+     * A vendor API level constant. It helps to unify the format of documenting {@code @since}
+     * block.
+     * <p>
+     * The added APIs for Vendor API level 3 are:
+     * <ul>
+     *     <li>{@link ActivityStack#getToken()}</li>
+     *     <li>{@link SplitInfo#getToken()}</li>
+     *     <li>{@link ActivityEmbeddingComponent#setLaunchingActivityStack(ActivityOptions,
+     *     IBinder)}</li>
+     *     <li>{@link ActivityEmbeddingComponent#invalidateTopVisibleSplitAttributes()}</li>
+     *     <li>{@link ActivityEmbeddingComponent#updateSplitAttributes(IBinder, SplitAttributes)}
+     *     </li>
+     *     <li>{@link ActivityEmbeddingComponent#finishActivityStacks(Set)}</li>
+     * </ul>
+     * </p>
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    int VENDOR_API_LEVEL_3 = 3;
+
     /**
      * Returns the API level of the vendor library on the device. If the returned version is not
      * supported by the WindowManager library, then some functions may not be available or replaced
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
index bdca977..121520c 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
@@ -17,6 +17,8 @@
 package androidx.window.extensions.embedding;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
+import android.os.IBinder;
 import android.view.WindowMetrics;
 
 import androidx.annotation.NonNull;
@@ -124,4 +126,60 @@
      * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
     void clearSplitAttributesCalculator();
+
+    /**
+     * Sets the launching {@link ActivityStack} to the given {@link ActivityOptions}.
+     *
+     * @param options The {@link ActivityOptions} to be updated.
+     * @param token The {@link ActivityStack#getToken()} to represent the {@link ActivityStack}
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    @NonNull
+    default ActivityOptions setLaunchingActivityStack(@NonNull ActivityOptions options,
+            @NonNull IBinder token) {
+        throw new UnsupportedOperationException("This method must not be called unless there is a"
+                + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Finishes a set of {@link ActivityStack}s. When an {@link ActivityStack} that was in an active
+     * split is finished, the other {@link ActivityStack} in the same {@link SplitInfo} can be
+     * expanded to fill the parent task container.
+     *
+     * @param activityStackTokens The set of tokens of {@link ActivityStack}-s that is going to be
+     *                            finished.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    default void finishActivityStacks(@NonNull Set<IBinder> activityStackTokens) {
+        throw new UnsupportedOperationException("This method must not be called unless there is a"
+                + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Triggers an update of the split attributes for the top split if there is one visible by
+     * making extensions invoke the split attributes calculator callback. This method can be used
+     * when a change to the split presentation originates from the application state change rather
+     * than driven by parent window changes or new activity starts. The call will be ignored if
+     * there is no visible split.
+     * @see #setSplitAttributesCalculator(Function)
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    default void invalidateTopVisibleSplitAttributes() {
+        throw new UnsupportedOperationException("This method must not be called unless there is a"
+                + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Updates the {@link SplitAttributes} of a split pair. This is an alternative to using
+     * a split attributes calculator callback, applicable when apps only need to update the
+     * splits in a few cases but rely on the default split attributes otherwise.
+     * @param splitInfoToken The identifier of the split pair to update.
+     * @param splitAttributes The {@link SplitAttributes} to apply to the split pair.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    default void updateSplitAttributes(@NonNull IBinder splitInfoToken,
+            @NonNull SplitAttributes splitAttributes) {
+        throw new UnsupportedOperationException("This method must not be called unless there is a"
+                + " corresponding override implementation on the device.");
+    }
 }
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
index 857738d..e568666 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
@@ -17,8 +17,12 @@
 package androidx.window.extensions.embedding;
 
 import android.app.Activity;
+import android.os.Binder;
+import android.os.IBinder;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.WindowExtensions;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -30,11 +34,17 @@
  */
 public class ActivityStack {
 
+    /** Only used for compatibility with the deprecated constructor. */
+    private static final IBinder INVALID_ACTIVITY_STACK_TOKEN = new Binder();
+
     @NonNull
     private final List<Activity> mActivities;
 
     private final boolean mIsEmpty;
 
+    @NonNull
+    private final IBinder mToken;
+
     /**
      * The {@code ActivityStack} constructor
      *
@@ -42,11 +52,24 @@
      *                   belongs to this {@code ActivityStack}
      * @param isEmpty Indicates whether there's any {@link Activity} running in this
      *                {@code ActivityStack}
+     * @param token The token to identify this {@code ActivityStack}
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
-    ActivityStack(@NonNull List<Activity> activities, boolean isEmpty) {
+    ActivityStack(@NonNull List<Activity> activities, boolean isEmpty, @NonNull IBinder token) {
         Objects.requireNonNull(activities);
+        Objects.requireNonNull(token);
         mActivities = new ArrayList<>(activities);
         mIsEmpty = isEmpty;
+        mToken = token;
+    }
+
+    /**
+     * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+     */
+    @Deprecated
+    ActivityStack(@NonNull List<Activity> activities, boolean isEmpty) {
+        this(activities, isEmpty, INVALID_ACTIVITY_STACK_TOKEN);
     }
 
     /**
@@ -76,19 +99,31 @@
         return mIsEmpty;
     }
 
+    /**
+     * Returns a token uniquely identifying the container.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @NonNull
+    public IBinder getToken() {
+        return mToken;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (!(o instanceof ActivityStack)) return false;
         ActivityStack that = (ActivityStack) o;
         return mActivities.equals(that.mActivities)
-                && mIsEmpty == that.mIsEmpty;
+                && mIsEmpty == that.mIsEmpty
+                && mToken.equals(that.mToken);
     }
 
     @Override
     public int hashCode() {
         int result = (mIsEmpty ? 1 : 0);
         result = result * 31 + mActivities.hashCode();
+        result = result * 31 + mToken.hashCode();
         return result;
     }
 
@@ -97,6 +132,7 @@
     public String toString() {
         return "ActivityStack{" + "mActivities=" + mActivities
                 + ", mIsEmpty=" + mIsEmpty
+                + ", mToken=" + mToken
                 + '}';
     }
 }
diff --git a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
index 33b8bb7..bac42a4 100644
--- a/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
+++ b/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
@@ -16,6 +16,9 @@
 
 package androidx.window.extensions.embedding;
 
+import android.os.Binder;
+import android.os.IBinder;
+
 import androidx.annotation.NonNull;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.embedding.SplitAttributes.SplitType;
@@ -25,6 +28,9 @@
 /** Describes a split of two containers with activities. */
 public class SplitInfo {
 
+    /** Only used for compatibility with the deprecated constructor. */
+    private static final IBinder INVALID_SPLIT_INFO_TOKEN = new Binder();
+
     @NonNull
     private final ActivityStack mPrimaryActivityStack;
     @NonNull
@@ -32,22 +38,42 @@
     @NonNull
     private final SplitAttributes mSplitAttributes;
 
+    @NonNull
+    private final IBinder mToken;
+
     /**
-     * The {@code SplitInfo} constructor.
+     * The {@code SplitInfo} constructor
      *
-     * @param primaryActivityStack The primary {@link ActivityStack}.
-     * @param secondaryActivityStack The secondary {@link ActivityStack}.
-     * @param splitAttributes The current {@link SplitAttributes} of this split pair.
+     * @param primaryActivityStack The primary {@link ActivityStack}
+     * @param secondaryActivityStack The secondary {@link ActivityStack}
+     * @param splitAttributes The current {@link SplitAttributes} of this split pair
+     * @param token The token to identify this split pair
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
     SplitInfo(@NonNull ActivityStack primaryActivityStack,
             @NonNull ActivityStack secondaryActivityStack,
-            @NonNull SplitAttributes splitAttributes) {
+            @NonNull SplitAttributes splitAttributes,
+            @NonNull IBinder token) {
         Objects.requireNonNull(primaryActivityStack);
         Objects.requireNonNull(secondaryActivityStack);
         Objects.requireNonNull(splitAttributes);
+        Objects.requireNonNull(token);
         mPrimaryActivityStack = primaryActivityStack;
         mSecondaryActivityStack = secondaryActivityStack;
         mSplitAttributes = splitAttributes;
+        mToken = token;
+    }
+
+    /**
+     * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+     */
+    @Deprecated
+    SplitInfo(@NonNull ActivityStack primaryActivityStack,
+            @NonNull ActivityStack secondaryActivityStack,
+            @NonNull SplitAttributes splitAttributes) {
+        this(primaryActivityStack, secondaryActivityStack, splitAttributes,
+                INVALID_SPLIT_INFO_TOKEN);
     }
 
     @NonNull
@@ -84,6 +110,15 @@
         return mSplitAttributes;
     }
 
+    /**
+     * Returns a token uniquely identifying the container.
+     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     */
+    @NonNull
+    public IBinder getToken() {
+        return mToken;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -91,7 +126,7 @@
         SplitInfo that = (SplitInfo) o;
         return mSplitAttributes.equals(that.mSplitAttributes) && mPrimaryActivityStack.equals(
                 that.mPrimaryActivityStack) && mSecondaryActivityStack.equals(
-                that.mSecondaryActivityStack);
+                that.mSecondaryActivityStack) && mToken.equals(that.mToken);
     }
 
     @Override
@@ -99,6 +134,7 @@
         int result = mPrimaryActivityStack.hashCode();
         result = result * 31 + mSecondaryActivityStack.hashCode();
         result = result * 31 + mSplitAttributes.hashCode();
+        result = result * 31 + mToken.hashCode();
         return result;
     }
 
@@ -109,6 +145,7 @@
                 + "mPrimaryActivityStack=" + mPrimaryActivityStack
                 + ", mSecondaryActivityStack=" + mSecondaryActivityStack
                 + ", mSplitAttributes=" + mSplitAttributes
+                + ", mToken=" + mToken
                 + '}';
     }
 }
diff --git a/window/extensions/extensions/src/test/resources/robolectric.properties b/window/extensions/extensions/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..69fde47
--- /dev/null
+++ b/window/extensions/extensions/src/test/resources/robolectric.properties
@@ -0,0 +1,3 @@
+# robolectric properties
+# Temporary until we update Robolectric to support API level 34.
+sdk=33
diff --git a/window/window-demos/demo/src/main/AndroidManifest.xml b/window/window-demos/demo/src/main/AndroidManifest.xml
index 5d3151e..dff69ac 100644
--- a/window/window-demos/demo/src/main/AndroidManifest.xml
+++ b/window/window-demos/demo/src/main/AndroidManifest.xml
@@ -58,7 +58,7 @@
             android:exported="false"
             android:configChanges="orientation|screenSize|screenLayout|screenSize"
             android:label="@string/window_metrics"/>
-        <activity android:name=".area.RearDisplayActivityConfigChanges"
+        <activity android:name=".RearDisplayActivityConfigChanges"
             android:exported="true"
             android:configChanges=
                 "orientation|screenLayout|screenSize|layoutDirection|smallestScreenSize"
@@ -248,6 +248,20 @@
             android:taskAffinity="androidx.window.demo.split_ime">
         </activity>
 
+        <!-- The demo app to show display configuration from different system callbacks. -->
+
+        <activity
+            android:name=".coresdk.WindowStateCallbackActivity"
+            android:exported="true"
+            android:label="Window State Callbacks"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
+            android:taskAffinity="androidx.window.demo.window_state_callback">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
         <!-- Activity embedding initializer -->
 
         <provider android:name="androidx.startup.InitializationProvider"
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt
new file mode 100644
index 0000000..3d35924
--- /dev/null
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/RearDisplayActivityConfigChanges.kt
@@ -0,0 +1,168 @@
+/*
+ * 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.window.demo
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.area.WindowAreaCapability
+import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_TRANSFER_ACTIVITY_TO_AREA
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_ACTIVE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_AVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNAVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNSUPPORTED
+import androidx.window.area.WindowAreaController
+import androidx.window.area.WindowAreaInfo
+import androidx.window.area.WindowAreaInfo.Type.Companion.TYPE_REAR_FACING
+import androidx.window.area.WindowAreaSession
+import androidx.window.area.WindowAreaSessionCallback
+import androidx.window.demo.common.infolog.InfoLogAdapter
+import androidx.window.demo.databinding.ActivityRearDisplayBinding
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import java.util.concurrent.Executor
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+/**
+ * Demo Activity that showcases listening for RearDisplay Status
+ * as well as enabling/disabling RearDisplay mode. This Activity
+ * implements [WindowAreaSessionCallback] for simplicity.
+ *
+ * This Activity overrides configuration changes for simplicity.
+ */
+class RearDisplayActivityConfigChanges : AppCompatActivity(), WindowAreaSessionCallback {
+
+    private lateinit var windowAreaController: WindowAreaController
+    private var rearDisplaySession: WindowAreaSession? = null
+    private var rearDisplayWindowAreaInfo: WindowAreaInfo? = null
+    private var rearDisplayStatus: WindowAreaCapability.Status = WINDOW_AREA_STATUS_UNSUPPORTED
+    private val infoLogAdapter = InfoLogAdapter()
+    private lateinit var binding: ActivityRearDisplayBinding
+    private lateinit var executor: Executor
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        binding = ActivityRearDisplayBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        executor = ContextCompat.getMainExecutor(this)
+        windowAreaController = WindowAreaController.getOrCreate()
+
+        binding.rearStatusRecyclerView.adapter = infoLogAdapter
+
+        binding.rearDisplayButton.setOnClickListener {
+            if (rearDisplayStatus == WINDOW_AREA_STATUS_ACTIVE) {
+                if (rearDisplaySession == null) {
+                    rearDisplaySession = rearDisplayWindowAreaInfo?.getActiveSession(
+                        OPERATION_TRANSFER_ACTIVITY_TO_AREA
+                    )
+                }
+                rearDisplaySession?.close()
+            } else {
+                rearDisplayWindowAreaInfo?.token?.let { token ->
+                    windowAreaController.transferActivityToWindowArea(
+                        token = token,
+                        activity = this,
+                        executor = executor,
+                        windowAreaSessionCallback = this)
+                }
+            }
+        }
+
+        lifecycleScope.launch(Dispatchers.Main) {
+            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                windowAreaController
+                    .windowAreaInfos
+                    .map { windowAreaInfoList -> windowAreaInfoList.firstOrNull {
+                        windowAreaInfo -> windowAreaInfo.type == TYPE_REAR_FACING
+                    } }
+                    .onEach { windowAreaInfo -> rearDisplayWindowAreaInfo = windowAreaInfo }
+                    .map(this@RearDisplayActivityConfigChanges::getRearDisplayStatus)
+                    .distinctUntilChanged()
+                    .collect { status ->
+                        infoLogAdapter.append(getCurrentTimeString(), status.toString())
+                        infoLogAdapter.notifyDataSetChanged()
+                        rearDisplayStatus = status
+                        updateRearDisplayButton()
+                    }
+            }
+        }
+    }
+
+    override fun onSessionStarted(session: WindowAreaSession) {
+        rearDisplaySession = session
+        infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has been started")
+        infoLogAdapter.notifyDataSetChanged()
+        updateRearDisplayButton()
+    }
+
+    override fun onSessionEnded(t: Throwable?) {
+        rearDisplaySession = null
+        infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has ended")
+        infoLogAdapter.notifyDataSetChanged()
+        updateRearDisplayButton()
+    }
+
+    private fun updateRearDisplayButton() {
+        if (rearDisplaySession != null) {
+            binding.rearDisplayButton.isEnabled = true
+            binding.rearDisplayButton.text = "Disable RearDisplay Mode"
+            return
+        }
+        when (rearDisplayStatus) {
+            WINDOW_AREA_STATUS_UNSUPPORTED -> {
+                binding.rearDisplayButton.isEnabled = false
+                binding.rearDisplayButton.text = "RearDisplay is not supported on this device"
+            }
+            WINDOW_AREA_STATUS_UNAVAILABLE -> {
+                binding.rearDisplayButton.isEnabled = false
+                binding.rearDisplayButton.text = "RearDisplay is not currently available"
+            }
+            WINDOW_AREA_STATUS_AVAILABLE -> {
+                binding.rearDisplayButton.isEnabled = true
+                binding.rearDisplayButton.text = "Enable RearDisplay Mode"
+            }
+            WINDOW_AREA_STATUS_ACTIVE -> {
+                binding.rearDisplayButton.isEnabled = true
+                binding.rearDisplayButton.text = "Disable RearDisplay Mode"
+            }
+        }
+    }
+
+    private fun getCurrentTimeString(): String {
+        val sdf = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault())
+        val currentDate = sdf.format(Date())
+        return currentDate.toString()
+    }
+
+    private fun getRearDisplayStatus(windowAreaInfo: WindowAreaInfo?): WindowAreaCapability.Status {
+        val status = windowAreaInfo?.getCapability(OPERATION_TRANSFER_ACTIVITY_TO_AREA)?.status
+        return status ?: WINDOW_AREA_STATUS_UNSUPPORTED
+    }
+
+    private companion object {
+        private val TAG = RearDisplayActivityConfigChanges::class.java.simpleName
+    }
+}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/area/RearDisplayActivityConfigChanges.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/area/RearDisplayActivityConfigChanges.kt
deleted file mode 100644
index edb2ed1..0000000
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/area/RearDisplayActivityConfigChanges.kt
+++ /dev/null
@@ -1,136 +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.window.demo.area
-
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.ContextCompat
-import androidx.core.util.Consumer
-import androidx.window.area.WindowAreaController
-import androidx.window.area.WindowAreaSession
-import androidx.window.area.WindowAreaSessionCallback
-import androidx.window.area.WindowAreaStatus
-import androidx.window.core.ExperimentalWindowApi
-import androidx.window.demo.common.infolog.InfoLogAdapter
-import androidx.window.demo.databinding.ActivityRearDisplayBinding
-import androidx.window.java.area.WindowAreaControllerJavaAdapter
-import java.text.SimpleDateFormat
-import java.util.Date
-import java.util.Locale
-import java.util.concurrent.Executor
-
-/**
- * Demo Activity that showcases listening for RearDisplay Status
- * as well as enabling/disabling RearDisplay mode. This Activity
- * implements [WindowAreaSessionCallback] for simplicity.
- *
- * This Activity overrides configuration changes for simplicity.
- */
-@OptIn(ExperimentalWindowApi::class)
-class RearDisplayActivityConfigChanges : AppCompatActivity(), WindowAreaSessionCallback {
-
-    private lateinit var windowAreaController: WindowAreaControllerJavaAdapter
-    private var rearDisplaySession: WindowAreaSession? = null
-    private val infoLogAdapter = InfoLogAdapter()
-    private lateinit var binding: ActivityRearDisplayBinding
-    private lateinit var executor: Executor
-
-    private val rearDisplayStatusListener = Consumer<WindowAreaStatus> { status ->
-        infoLogAdapter.append(getCurrentTimeString(), status.toString())
-        infoLogAdapter.notifyDataSetChanged()
-        updateRearDisplayButton(status)
-    }
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        binding = ActivityRearDisplayBinding.inflate(layoutInflater)
-        setContentView(binding.root)
-
-        executor = ContextCompat.getMainExecutor(this)
-        windowAreaController = WindowAreaControllerJavaAdapter(WindowAreaController.getOrCreate())
-
-        binding.rearStatusRecyclerView.adapter = infoLogAdapter
-
-        binding.rearDisplayButton.setOnClickListener {
-            if (rearDisplaySession != null) {
-                rearDisplaySession?.close()
-            } else {
-                windowAreaController.startRearDisplayModeSession(
-                    this,
-                    executor,
-                    this)
-            }
-        }
-    }
-
-    override fun onStart() {
-        super.onStart()
-        windowAreaController.addRearDisplayStatusListener(
-            executor,
-            rearDisplayStatusListener
-        )
-    }
-
-    override fun onStop() {
-        super.onStop()
-        windowAreaController.removeRearDisplayStatusListener(rearDisplayStatusListener)
-    }
-
-    override fun onSessionStarted(session: WindowAreaSession) {
-        rearDisplaySession = session
-        infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has been started")
-        infoLogAdapter.notifyDataSetChanged()
-    }
-
-    override fun onSessionEnded() {
-        rearDisplaySession = null
-        infoLogAdapter.append(getCurrentTimeString(), "RearDisplay Session has ended")
-        infoLogAdapter.notifyDataSetChanged()
-    }
-
-    private fun updateRearDisplayButton(status: WindowAreaStatus) {
-        if (rearDisplaySession != null) {
-            binding.rearDisplayButton.isEnabled = true
-            binding.rearDisplayButton.text = "Disable RearDisplay Mode"
-            return
-        }
-        when (status) {
-            WindowAreaStatus.UNSUPPORTED -> {
-                binding.rearDisplayButton.isEnabled = false
-                binding.rearDisplayButton.text = "RearDisplay is not supported on this device"
-            }
-            WindowAreaStatus.UNAVAILABLE -> {
-                binding.rearDisplayButton.isEnabled = false
-                binding.rearDisplayButton.text = "RearDisplay is not currently available"
-            }
-            WindowAreaStatus.AVAILABLE -> {
-                binding.rearDisplayButton.isEnabled = true
-                binding.rearDisplayButton.text = "Enable RearDisplay Mode"
-            }
-        }
-    }
-
-    private fun getCurrentTimeString(): String {
-        val sdf = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault())
-        val currentDate = sdf.format(Date())
-        return currentDate.toString()
-    }
-
-    private companion object {
-        private val TAG = RearDisplayActivityConfigChanges::class.java.simpleName
-    }
-}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateCallbackActivity.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateCallbackActivity.kt
new file mode 100644
index 0000000..bd39f74
--- /dev/null
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateCallbackActivity.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.window.demo.coresdk
+
+import android.content.Context
+import android.content.res.Configuration
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManager.DisplayListener
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.window.demo.databinding.ActivityCoresdkWindowStateCallbackLayoutBinding
+import androidx.window.layout.WindowInfoTracker
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+/** Activity to show display configuration from different system callbacks. */
+class WindowStateCallbackActivity : AppCompatActivity() {
+
+    private lateinit var displayManager: DisplayManager
+    private lateinit var handler: Handler
+
+    private lateinit var latestUpdateView: WindowStateView
+    private lateinit var displayListenerView: WindowStateView
+    private lateinit var activityConfigurationView: WindowStateView
+    private lateinit var displayFeatureView: WindowStateView
+
+    /**
+     * Runnable to poll configuration every 500ms.
+     * To always provide an up-to-date configuration so it can be used to verify the configurations
+     * from other callbacks.
+     */
+    private val updateWindowStateIfChanged = object : Runnable {
+        override fun run() {
+            latestUpdateView.onWindowStateCallbackInvoked()
+            handler.postDelayed(this, 500)
+        }
+    }
+
+    private val displayListener = object : DisplayListener {
+        override fun onDisplayAdded(displayId: Int) {
+        }
+
+        override fun onDisplayRemoved(displayId: Int) {
+        }
+
+        override fun onDisplayChanged(displayId: Int) {
+            if (displayId == DEFAULT_DISPLAY) {
+                displayListenerView.onWindowStateCallbackInvoked()
+            }
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val viewBinding = ActivityCoresdkWindowStateCallbackLayoutBinding.inflate(layoutInflater)
+        setContentView(viewBinding.root)
+        latestUpdateView = viewBinding.latestUpdateView
+        displayListenerView = viewBinding.displayListenerView
+        activityConfigurationView = viewBinding.activityConfigurationView
+        displayFeatureView = viewBinding.displayFeatureView
+
+        displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+        handler = Handler(Looper.getMainLooper())
+        displayManager.registerDisplayListener(displayListener, handler)
+        // Collect windowInfo when STARTED and stop when STOPPED.
+        lifecycleScope.launch(Dispatchers.Main) {
+            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                WindowInfoTracker.getOrCreate(this@WindowStateCallbackActivity)
+                    .windowLayoutInfo(this@WindowStateCallbackActivity)
+                    .collect { _ ->
+                        displayFeatureView.onWindowStateCallbackInvoked()
+                    }
+            }
+        }
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        displayManager.unregisterDisplayListener(displayListener)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        // Start polling the configuration every 500ms.
+        updateWindowStateIfChanged.run()
+    }
+
+    override fun onPause() {
+        super.onPause()
+        handler.removeCallbacks(updateWindowStateIfChanged)
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        activityConfigurationView.onWindowStateCallbackInvoked()
+    }
+}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateConfigView.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateConfigView.kt
new file mode 100644
index 0000000..4a18150
--- /dev/null
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateConfigView.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.window.demo.coresdk
+
+import android.content.Context
+import android.graphics.Color
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.window.demo.R
+import androidx.window.demo.databinding.WindowStateConfigViewBinding
+
+/** View to show a display configuration value. */
+class WindowStateConfigView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+    private val configView: TextView
+    private var configValue: String? = null
+
+    /** Whether to highlight the value when it is changed. */
+    var shouldHighlightChange = false
+
+    init {
+        val viewBinding = WindowStateConfigViewBinding.inflate(LayoutInflater.from(context),
+            this, true)
+        configView = viewBinding.configValue
+        context.theme.obtainStyledAttributes(
+            attrs,
+            R.styleable.WindowStateConfigView,
+            0, 0).apply {
+            try {
+                getString(R.styleable.WindowStateConfigView_configName)?.let {
+                    viewBinding.configName.text = it
+                }
+            } finally {
+                recycle()
+            }
+        }
+    }
+
+    /** Updates the config value. */
+    fun updateValue(value: String) {
+        if (shouldHighlightChange && configValue != null && configValue != value) {
+            // Highlight previous value if changed.
+            configView.setTextColor(Color.RED)
+        } else {
+            configView.setTextColor(Color.BLACK)
+        }
+        configValue = value
+        configView.text = value
+    }
+}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateView.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateView.kt
new file mode 100644
index 0000000..c569e8f
--- /dev/null
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/coresdk/WindowStateView.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.window.demo.coresdk
+
+import android.content.Context
+import android.graphics.Rect
+import android.hardware.display.DisplayManager
+import android.util.AttributeSet
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.LayoutInflater
+import android.view.WindowManager
+import android.widget.LinearLayout
+import androidx.window.demo.R
+import androidx.window.demo.databinding.WindowStateViewBinding
+import java.text.SimpleDateFormat
+import java.util.Date
+
+/** View to show the display configuration from the latest update. */
+class WindowStateView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+
+    private val displayManager: DisplayManager
+    private val windowManager: WindowManager
+
+    private val timestampView: WindowStateConfigView
+    private val displayRotationView: WindowStateConfigView
+    private val displayBoundsView: WindowStateConfigView
+    private val prevDisplayRotationView: WindowStateConfigView
+    private val prevDisplayBoundsView: WindowStateConfigView
+
+    private val shouldHidePrevConfig: Boolean
+    private var lastDisplayRotation = -1
+    private val lastDisplayBounds = Rect()
+
+    init {
+        displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+        windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+
+        val viewBinding = WindowStateViewBinding.inflate(LayoutInflater.from(context), this, true)
+        timestampView = viewBinding.timestampView
+        displayRotationView = viewBinding.displayRotationView
+        displayBoundsView = viewBinding.displayBoundsView
+        prevDisplayRotationView = viewBinding.prevDisplayRotationView
+        prevDisplayBoundsView = viewBinding.prevDisplayBoundsView
+
+        context.theme.obtainStyledAttributes(
+            attrs,
+            R.styleable.WindowStateView,
+            0, 0).apply {
+            try {
+                getString(R.styleable.WindowStateView_title)?.let {
+                    viewBinding.callbackTitle.text = it
+                }
+                shouldHidePrevConfig = getBoolean(
+                    R.styleable.WindowStateView_hidePrevConfig,
+                    false)
+                if (shouldHidePrevConfig) {
+                    timestampView.visibility = GONE
+                    displayRotationView.shouldHighlightChange = false
+                    displayBoundsView.shouldHighlightChange = false
+                    prevDisplayRotationView.visibility = GONE
+                    prevDisplayBoundsView.visibility = GONE
+                } else {
+                    displayRotationView.shouldHighlightChange = true
+                    displayBoundsView.shouldHighlightChange = true
+                }
+            } finally {
+                recycle()
+            }
+        }
+    }
+
+    /** Called when the corresponding system callback is invoked. */
+    fun onWindowStateCallbackInvoked() {
+        val displayRotation = displayManager.getDisplay(DEFAULT_DISPLAY).rotation
+        val displayBounds = windowManager.maximumWindowMetrics.bounds
+
+        if (shouldHidePrevConfig &&
+            displayRotation == lastDisplayRotation &&
+            displayBounds == lastDisplayBounds) {
+            // Skip if the state is unchanged.
+            return
+        }
+
+        timestampView.updateValue(TIME_FORMAT.format(Date()))
+        displayRotationView.updateValue(displayRotation.toString())
+        displayBoundsView.updateValue(displayBounds.toString())
+
+        if (!shouldHidePrevConfig && lastDisplayRotation != -1) {
+            // Skip if there is no previous value.
+            prevDisplayRotationView.updateValue(lastDisplayRotation.toString())
+            prevDisplayBoundsView.updateValue(lastDisplayBounds.toString())
+        }
+
+        lastDisplayRotation = displayRotation
+        lastDisplayBounds.set(displayBounds)
+    }
+
+    companion object {
+        private val TIME_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
+    }
+}
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
index a5fe754..505a365 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/ExampleWindowInitializer.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import androidx.startup.Initializer
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.demo.R
 import androidx.window.demo.embedding.SplitDeviceStateActivityBase.Companion.SUFFIX_AND_FULLSCREEN_IN_BOOK_MODE
 import androidx.window.demo.embedding.SplitDeviceStateActivityBase.Companion.SUFFIX_AND_HORIZONTAL_LAYOUT_IN_TABLETOP
@@ -46,7 +45,6 @@
 /**
  * Initializes SplitController with a set of statically defined rules.
  */
-@OptIn(ExperimentalWindowApi::class)
 class ExampleWindowInitializer : Initializer<RuleController> {
 
     override fun create(context: Context): RuleController {
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
index 8e0c564..faf792e 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitActivityBase.java
@@ -24,6 +24,7 @@
 import static androidx.window.embedding.SplitRule.FinishBehavior.NEVER;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -41,6 +42,7 @@
 import androidx.window.demo.R;
 import androidx.window.demo.databinding.ActivitySplitActivityLayoutBinding;
 import androidx.window.embedding.ActivityEmbeddingController;
+import androidx.window.embedding.ActivityEmbeddingOptions;
 import androidx.window.embedding.ActivityFilter;
 import androidx.window.embedding.ActivityRule;
 import androidx.window.embedding.EmbeddingRule;
@@ -96,8 +98,23 @@
             bStartIntent.putExtra(EXTRA_LAUNCH_C_TO_SIDE, true);
             startActivity(bStartIntent);
         });
-        mViewBinding.launchE.setOnClickListener((View v) ->
-                startActivity(new Intent(this, SplitActivityE.class)));
+        mViewBinding.launchE.setOnClickListener((View v) -> {
+            Bundle bundle = null;
+            if (mViewBinding.setLaunchingEInActivityStack.isChecked()) {
+                try {
+                    final ActivityOptions options = ActivityEmbeddingOptions
+                            .setLaunchingActivityStack(ActivityOptions.makeBasic(), this);
+                    bundle = options.toBundle();
+                } catch (UnsupportedOperationException ex) {
+                    Log.w(TAG, "#setLaunchingActivityStack is not supported", ex);
+                }
+            }
+            startActivity(new Intent(this, SplitActivityE.class), bundle);
+        });
+        if (!ActivityEmbeddingOptions.isSetLaunchingActivityStackSupported(
+                ActivityOptions.makeBasic())) {
+            mViewBinding.setLaunchingEInActivityStack.setEnabled(false);
+        }
         mViewBinding.launchF.setOnClickListener((View v) ->
                 startActivity(new Intent(this, SplitActivityF.class)));
         mViewBinding.launchFPendingIntent.setOnClickListener((View v) -> {
diff --git a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
index 9f80a5f..e95997c 100644
--- a/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
+++ b/window/window-demos/demo/src/main/java/androidx/window/demo/embedding/SplitDeviceStateActivityBase.kt
@@ -28,7 +28,6 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.demo.R
 import androidx.window.demo.databinding.ActivitySplitDeviceStateLayoutBinding
 import androidx.window.embedding.EmbeddingRule
@@ -45,7 +44,6 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
-@OptIn(ExperimentalWindowApi::class)
 open class SplitDeviceStateActivityBase : AppCompatActivity(), View.OnClickListener,
     RadioGroup.OnCheckedChangeListener, CompoundButton.OnCheckedChangeListener,
     AdapterView.OnItemSelectedListener {
diff --git a/window/window-demos/demo/src/main/res/layout/activity_coresdk_window_state_callback_layout.xml b/window/window-demos/demo/src/main/res/layout/activity_coresdk_window_state_callback_layout.xml
new file mode 100644
index 0000000..64c3b56
--- /dev/null
+++ b/window/window-demos/demo/src/main/res/layout/activity_coresdk_window_state_callback_layout.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/root_split_activity_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="10dp">
+
+        <!-- Update to the latest configuration. -->
+        <androidx.window.demo.coresdk.WindowStateView
+            android:id="@+id/latest_update_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:title="@string/latest_configuration_title"
+            app:hidePrevConfig="true"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_marginTop="10dp"
+            android:layout_marginBottom="10dp"
+            android:background="#AAAAAA" />
+
+        <!-- Update from DisplayListener. -->
+        <androidx.window.demo.coresdk.WindowStateView
+            android:id="@+id/display_listener_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:title="@string/display_listener_title"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_marginTop="10dp"
+            android:layout_marginBottom="10dp"
+            android:background="#AAAAAA" />
+
+        <!-- Update from Activity#onConfigurationChanged. -->
+        <androidx.window.demo.coresdk.WindowStateView
+            android:id="@+id/activity_configuration_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:title="@string/activity_configuration_title"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_marginTop="10dp"
+            android:layout_marginBottom="10dp"
+            android:background="#AAAAAA" />
+
+        <!-- Update from WindowInfoTracker. -->
+        <androidx.window.demo.coresdk.WindowStateView
+            android:id="@+id/display_feature_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:title="@string/display_feature_title"/>
+
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/res/layout/activity_split_device_state_layout.xml b/window/window-demos/demo/src/main/res/layout/activity_split_device_state_layout.xml
index 099490a..dcc8ab4 100644
--- a/window/window-demos/demo/src/main/res/layout/activity_split_device_state_layout.xml
+++ b/window/window-demos/demo/src/main/res/layout/activity_split_device_state_layout.xml
@@ -161,4 +161,4 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
     </LinearLayout>
-</ScrollView>
+</ScrollView>
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/res/layout/window_state_config_view.xml b/window/window-demos/demo/src/main/res/layout/window_state_config_view.xml
new file mode 100644
index 0000000..6a97d8f
--- /dev/null
+++ b/window/window-demos/demo/src/main/res/layout/window_state_config_view.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="5dp"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/config_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textStyle="bold"
+        android:text="@string/window_state_placeholder"/>
+
+    <TextView
+        android:id="@+id/config_value"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/window_state_placeholder"
+        android:layout_marginLeft="10dp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/res/layout/window_state_view.xml b/window/window-demos/demo/src/main/res/layout/window_state_view.xml
new file mode 100644
index 0000000..1944b95
--- /dev/null
+++ b/window/window-demos/demo/src/main/res/layout/window_state_view.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <!-- Callback name -->
+    <TextView
+        android:id="@+id/callback_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="@android:style/TextAppearance.Material.Title"
+        android:text="@string/window_state_placeholder"/>
+
+    <!-- Last update timestamp -->
+    <androidx.window.demo.coresdk.WindowStateConfigView
+        android:id="@+id/timestamp_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:configName="@string/timestamp_title"/>
+
+    <!-- Display rotation -->
+    <androidx.window.demo.coresdk.WindowStateConfigView
+        android:id="@+id/display_rotation_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:configName="@string/display_rotation_title"/>
+
+    <!-- Display bounds -->
+    <androidx.window.demo.coresdk.WindowStateConfigView
+        android:id="@+id/display_bounds_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:configName="@string/display_bounds_title"/>
+
+    <!-- Previous Display rotation -->
+    <androidx.window.demo.coresdk.WindowStateConfigView
+        android:id="@+id/prev_display_rotation_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:configName="@string/prev_display_rotation_title"/>
+
+    <!-- Previous Display bounds -->
+    <androidx.window.demo.coresdk.WindowStateConfigView
+        android:id="@+id/prev_display_bounds_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:configName="@string/prev_display_bounds_title"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/res/values/attrs.xml b/window/window-demos/demo/src/main/res/values/attrs.xml
index 8a29d91..34b783a 100644
--- a/window/window-demos/demo/src/main/res/values/attrs.xml
+++ b/window/window-demos/demo/src/main/res/values/attrs.xml
@@ -20,4 +20,13 @@
         <attr name="startViewId" format="reference" />
         <attr name="endViewId" format="reference" />
     </declare-styleable>
+
+    <declare-styleable name="WindowStateView">
+        <attr name="title" format="string" />
+        <attr name="hidePrevConfig" format="boolean" />
+    </declare-styleable>
+
+    <declare-styleable name="WindowStateConfigView">
+        <attr name="configName" format="string" />
+    </declare-styleable>
 </resources>
\ No newline at end of file
diff --git a/window/window-demos/demo/src/main/res/values/strings.xml b/window/window-demos/demo/src/main/res/values/strings.xml
index 1a86d90..e9ce55f 100644
--- a/window/window-demos/demo/src/main/res/values/strings.xml
+++ b/window/window-demos/demo/src/main/res/values/strings.xml
@@ -58,4 +58,14 @@
     <string name="ime_button_switch_default">Switch default IME</string>
     <string name="install_samples_2">Install window-demos:demo-second-app to launch activities from a different UID.</string>
     <string name="toast_split_not_support">Please enable PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED and ensure device supports splits.</string>
+    <string name="latest_configuration_title">Latest Configuration</string>
+    <string name="display_listener_title">DisplayListener#onDisplayChanged</string>
+    <string name="activity_configuration_title">Activity#onConfigurationChanged</string>
+    <string name="display_feature_title">WindowInfoTracker</string>
+    <string name="timestamp_title">Timestamp:</string>
+    <string name="display_rotation_title">Display Rotation:</string>
+    <string name="display_bounds_title">Display Bounds:</string>
+    <string name="prev_display_rotation_title">Previous Display Rotation:</string>
+    <string name="prev_display_bounds_title">Previous Display Bounds:</string>
+    <string name="window_state_placeholder">N/A</string>
 </resources>
diff --git a/window/window-java/api/current.txt b/window/window-java/api/current.txt
index d621966..d443b31 100644
--- a/window/window-java/api/current.txt
+++ b/window/window-java/api/current.txt
@@ -1,4 +1,14 @@
 // Signature format: 4.0
+package androidx.window.java.area {
+
+  public final class WindowAreaControllerCallbackAdapter implements androidx.window.area.WindowAreaController {
+    ctor public WindowAreaControllerCallbackAdapter(androidx.window.area.WindowAreaController controller);
+    method public void addWindowAreaInfoListListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+    method public void removeWindowAreaInfoListListener(androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+  }
+
+}
+
 package androidx.window.java.embedding {
 
   @androidx.window.core.ExperimentalWindowApi public final class SplitControllerCallbackAdapter {
diff --git a/window/window-java/api/restricted_current.txt b/window/window-java/api/restricted_current.txt
index d621966..d443b31 100644
--- a/window/window-java/api/restricted_current.txt
+++ b/window/window-java/api/restricted_current.txt
@@ -1,4 +1,14 @@
 // Signature format: 4.0
+package androidx.window.java.area {
+
+  public final class WindowAreaControllerCallbackAdapter implements androidx.window.area.WindowAreaController {
+    ctor public WindowAreaControllerCallbackAdapter(androidx.window.area.WindowAreaController controller);
+    method public void addWindowAreaInfoListListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+    method public void removeWindowAreaInfoListListener(androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+  }
+
+}
+
 package androidx.window.java.embedding {
 
   @androidx.window.core.ExperimentalWindowApi public final class SplitControllerCallbackAdapter {
diff --git a/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerCallbackAdapter.kt b/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerCallbackAdapter.kt
new file mode 100644
index 0000000..09c8292
--- /dev/null
+++ b/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerCallbackAdapter.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.window.java.area
+
+import androidx.core.util.Consumer
+import androidx.window.area.WindowAreaController
+import androidx.window.area.WindowAreaInfo
+import java.util.concurrent.Executor
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.launch
+
+/**
+ * An adapter for [WindowAreaController] to provide callback APIs.
+ */
+class WindowAreaControllerCallbackAdapter(
+    private val controller: WindowAreaController
+) : WindowAreaController by controller {
+
+    /**
+     * A [ReentrantLock] to protect against concurrent access to [consumerToJobMap].
+     */
+    private val lock = ReentrantLock()
+    private val consumerToJobMap = mutableMapOf<Consumer<*>, Job>()
+
+    /**
+     * Registers a listener that is interested in the current list of [WindowAreaInfo] available to
+     * be interacted with.
+     *
+     * The [listener] will receive an initial value on registration, as soon as it becomes
+     * available.
+     *
+     * @param executor to handle sending listener updates.
+     * @param listener to receive updates to the list of [WindowAreaInfo].
+     * @see WindowAreaController.transferActivityToWindowArea
+     * @see WindowAreaController.presentContentOnWindowArea
+     */
+    fun addWindowAreaInfoListListener(
+        executor: Executor,
+        listener: Consumer<List<WindowAreaInfo>>
+    ) {
+        // TODO(274013517): Extract adapter pattern out of each class
+        val statusFlow = controller.windowAreaInfos
+        lock.withLock {
+            if (consumerToJobMap[listener] == null) {
+                val scope = CoroutineScope(executor.asCoroutineDispatcher())
+                consumerToJobMap[listener] = scope.launch {
+                    statusFlow.collect { listener.accept(it) }
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes a listener of available [WindowAreaInfo] records. If the listener is not present then
+     * this method is a no-op.
+     *
+     * @param listener to remove from receiving status updates.
+     * @see WindowAreaController.transferActivityToWindowArea
+     * @see WindowAreaController.presentContentOnWindowArea
+     */
+    fun removeWindowAreaInfoListListener(listener: Consumer<List<WindowAreaInfo>>) {
+        lock.withLock {
+            consumerToJobMap[listener]?.cancel()
+            consumerToJobMap.remove(listener)
+        }
+    }
+ }
\ No newline at end of file
diff --git a/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt b/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt
deleted file mode 100644
index 3ea0c05..0000000
--- a/window/window-java/src/main/java/androidx/window/java/area/WindowAreaControllerJavaAdapter.kt
+++ /dev/null
@@ -1,128 +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.window.java.area
-
-import android.app.Activity
-import androidx.core.util.Consumer
-import androidx.window.area.WindowAreaController
-import androidx.window.area.WindowAreaSessionCallback
-import androidx.window.area.WindowAreaStatus
-import androidx.window.core.ExperimentalWindowApi
-import java.util.concurrent.Executor
-import java.util.concurrent.locks.ReentrantLock
-import kotlin.concurrent.withLock
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.asCoroutineDispatcher
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-
-/**
- * An adapted interface for [WindowAreaController] that provides the information and
- * functionality around RearDisplay Mode via a callback shaped API.
- *
- * @hide
- *
- */
-@ExperimentalWindowApi
-class WindowAreaControllerJavaAdapter(
-    private val controller: WindowAreaController
-) : WindowAreaController by controller {
-
-    /**
-     * A [ReentrantLock] to protect against concurrent access to [consumerToJobMap].
-     */
-    private val lock = ReentrantLock()
-    private val consumerToJobMap = mutableMapOf<Consumer<*>, Job>()
-
-    /**
-     * Registers a listener to consume [WindowAreaStatus] values defined as
-     * [WindowAreaStatus.UNSUPPORTED], [WindowAreaStatus.UNAVAILABLE], and
-     * [WindowAreaStatus.AVAILABLE]. The values provided through this listener should be used
-     * to determine if you are able to enable rear display Mode at that time. You can use these
-     * values to modify your UI to show/hide controls and determine when to enable features
-     * that use rear display Mode. You should only try and enter rear display mode when your
-     * [consumer] is provided a value of [WindowAreaStatus.AVAILABLE].
-     *
-     * The [consumer] will be provided an initial value on registration, as well as any change
-     * to the status as they occur. This could happen due to hardware device state changes, or if
-     * another process has enabled RearDisplay Mode.
-     *
-     * @see WindowAreaController.rearDisplayStatus
-     */
-    fun addRearDisplayStatusListener(
-        executor: Executor,
-        consumer: Consumer<WindowAreaStatus>
-    ) {
-        val statusFlow = controller.rearDisplayStatus()
-        lock.withLock {
-            if (consumerToJobMap[consumer] == null) {
-                val scope = CoroutineScope(executor.asCoroutineDispatcher())
-                consumerToJobMap[consumer] = scope.launch {
-                    statusFlow.collect { consumer.accept(it) }
-                }
-            }
-        }
-    }
-
-    /**
-     * Removes a listener of [WindowAreaStatus] values
-     * @see WindowAreaController.rearDisplayStatus
-     */
-    fun removeRearDisplayStatusListener(consumer: Consumer<WindowAreaStatus>) {
-        lock.withLock {
-            consumerToJobMap[consumer]?.cancel()
-            consumerToJobMap.remove(consumer)
-        }
-    }
-
-    /**
-     * Starts a RearDisplay Mode session and provides updates through the
-     * [WindowAreaSessionCallback] provided. Due to the nature of moving your Activity to a
-     * different display, your Activity will likely go through a configuration change. Because of
-     * this, if your Activity does not override configuration changes, this method should be called
-     * from a component that outlives the Activity lifecycle such as a
-     * [androidx.lifecycle.ViewModel]. If your Activity does override
-     * configuration changes, it is safe to call this method inside your Activity.
-     *
-     * This method should only be called if you have received a [WindowAreaStatus.AVAILABLE]
-     * value from the listener provided through the [addRearDisplayStatusListener] method. If
-     * you try and enable RearDisplay mode without it being available, you will receive an
-     * [UnsupportedOperationException].
-     *
-     * The [windowAreaSessionCallback] provided will receive a call to
-     * [WindowAreaSessionCallback.onSessionStarted] after your Activity has been moved to the
-     * display corresponding to this mode. RearDisplay mode will stay active until the session
-     * provided through [WindowAreaSessionCallback.onSessionStarted] is closed, or there is a device
-     * state change that makes RearDisplay mode incompatible such as if the device is closed so the
-     * outer-display is no longer in line with the rear camera. When this occurs,
-     * [WindowAreaSessionCallback.onSessionEnded] is called to notify you the session has been
-     * ended.
-     *
-     * @see addRearDisplayStatusListener
-     * @throws UnsupportedOperationException if you try and start a RearDisplay session when
-     * your [WindowAreaController.rearDisplayStatus] does not return a value of
-     * [WindowAreaStatus.AVAILABLE]
-     */
-    fun startRearDisplayModeSession(
-        activity: Activity,
-        executor: Executor,
-        windowAreaSessionCallback: WindowAreaSessionCallback
-    ) {
-        controller.rearDisplayMode(activity, executor, windowAreaSessionCallback)
-    }
-}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/embedding/ActivityStackTesting.kt b/window/window-testing/src/main/java/androidx/window/testing/embedding/ActivityStackTesting.kt
index ef38d1a..879ed68 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/embedding/ActivityStackTesting.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/embedding/ActivityStackTesting.kt
@@ -18,6 +18,9 @@
 package androidx.window.testing.embedding
 
 import android.app.Activity
+import android.os.Binder
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
 import androidx.window.embedding.ActivityStack
 
 /**
@@ -37,4 +40,9 @@
 fun TestActivityStack(
     activitiesInProcess: List<Activity> = emptyList(),
     isEmpty: Boolean = false,
-): ActivityStack = ActivityStack(activitiesInProcess, isEmpty)
\ No newline at end of file
+): ActivityStack = ActivityStack(activitiesInProcess, isEmpty, TEST_ACTIVITY_STACK_TOKEN)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@VisibleForTesting
+@JvmField
+val TEST_ACTIVITY_STACK_TOKEN = Binder()
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTesting.kt b/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTesting.kt
index dd17311..4b39749 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTesting.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTesting.kt
@@ -18,7 +18,6 @@
 package androidx.window.testing.embedding
 
 import android.content.res.Configuration
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.embedding.SplitAttributes
 import androidx.window.embedding.SplitAttributesCalculatorParams
 import androidx.window.embedding.SplitController
@@ -55,7 +54,6 @@
  *
  * @see SplitAttributesCalculatorParams
  */
-@OptIn(ExperimentalWindowApi::class)
 @Suppress("FunctionName")
 @JvmName("createTestSplitAttributesCalculatorParams")
 @JvmOverloads
diff --git a/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitInfoTesting.kt b/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitInfoTesting.kt
index e3d3ac9..1ed7844 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitInfoTesting.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/embedding/SplitInfoTesting.kt
@@ -17,6 +17,7 @@
 
 package androidx.window.testing.embedding
 
+import android.os.Binder
 import androidx.window.embedding.ActivityStack
 import androidx.window.embedding.SplitAttributes
 import androidx.window.embedding.SplitInfo
@@ -42,4 +43,11 @@
     primaryActivityStack: ActivityStack = TestActivityStack(),
     secondActivityStack: ActivityStack = TestActivityStack(),
     splitAttributes: SplitAttributes = SplitAttributes.Builder().build(),
-): SplitInfo = SplitInfo(primaryActivityStack, secondActivityStack, splitAttributes)
\ No newline at end of file
+): SplitInfo = SplitInfo(
+    primaryActivityStack,
+    secondActivityStack,
+    splitAttributes,
+    TEST_SPLIT_INFO_TOKEN
+)
+
+private val TEST_SPLIT_INFO_TOKEN = Binder()
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt b/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
index 3b77116..78aca27 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/embedding/StubEmbeddingBackend.kt
@@ -17,8 +17,10 @@
 package androidx.window.testing.embedding
 
 import android.app.Activity
+import android.app.ActivityOptions
+import android.os.IBinder
 import androidx.core.util.Consumer
-import androidx.window.core.ExperimentalWindowApi
+import androidx.window.embedding.ActivityStack
 import androidx.window.embedding.EmbeddingBackend
 import androidx.window.embedding.EmbeddingRule
 import androidx.window.embedding.SplitAttributes
@@ -147,7 +149,6 @@
     override fun isActivityEmbedded(activity: Activity): Boolean =
         embeddedActivities.contains(activity)
 
-    @ExperimentalWindowApi
     override fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -162,6 +163,37 @@
         TODO("Not yet implemented")
     }
 
+    override fun getActivityStack(activity: Activity): ActivityStack? {
+        TODO("Not yet implemented")
+    }
+
+    override fun setLaunchingActivityStack(
+        options: ActivityOptions,
+        token: IBinder
+    ): ActivityOptions {
+        TODO("Not yet implemented")
+    }
+
+    override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
+        TODO("Not yet implemented")
+    }
+
+    override fun isFinishActivityStacksSupported(): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun invalidateTopVisibleSplitAttributes() {
+        TODO("Not yet implemented")
+    }
+
+    override fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes) {
+        TODO("Not yet implemented")
+    }
+
+    override fun areSplitAttributesUpdatesSupported(): Boolean {
+        TODO("Not yet implemented")
+    }
+
     private fun validateRules(rules: Set<EmbeddingRule>) {
         val tags = HashSet<String>()
         rules.forEach { rule ->
@@ -174,4 +206,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingJavaTest.java b/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingJavaTest.java
index ca3d9c4..e946b53 100644
--- a/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingJavaTest.java
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingJavaTest.java
@@ -40,8 +40,8 @@
     public void testActivityStackDefaultValue() {
         final ActivityStack activityStack = TestActivityStack.createTestActivityStack();
 
-        assertEquals(new ActivityStack(Collections.emptyList(), false /* isEmpty */),
-                activityStack);
+        assertEquals(new ActivityStack(Collections.emptyList(), false /* isEmpty */,
+                TestActivityStack.TEST_ACTIVITY_STACK_TOKEN), activityStack);
     }
 
     /** Verifies {@link TestActivityStack} */
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingTest.kt b/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingTest.kt
index 905bb8f..487aeab 100644
--- a/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingTest.kt
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/ActivityStackTestingTest.kt
@@ -34,7 +34,10 @@
     fun testActivityStackDefaultValue() {
         val activityStack = TestActivityStack()
 
-        assertEquals(ActivityStack(emptyList(), isEmpty = false), activityStack)
+        assertEquals(
+            ActivityStack(emptyList(), isEmpty = false, TEST_ACTIVITY_STACK_TOKEN),
+            activityStack
+        )
     }
 
     /** Verifies [TestActivityStack] */
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingJavaTest.java b/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingJavaTest.java
index c2bb377..27e70c2 100644
--- a/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingJavaTest.java
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingJavaTest.java
@@ -48,7 +48,6 @@
 import java.util.List;
 
 /** Test class to verify {@link TestSplitAttributesCalculatorParams} in Java. */
-@OptIn(markerClass = ExperimentalWindowApi.class)
 @RunWith(RobolectricTestRunner.class)
 public class SplitAttributesCalculatorParamsTestingJavaTest {
     private static final Rect TEST_BOUNDS = new Rect(0, 0, 2000, 2000);
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingTest.kt b/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingTest.kt
index 66dc2e8..b4d1e35 100644
--- a/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingTest.kt
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/SplitAttributesCalculatorParamsTestingTest.kt
@@ -37,7 +37,6 @@
 import org.robolectric.RobolectricTestRunner
 
 /** Test class to verify [TestSplitAttributesCalculatorParams]. */
-@OptIn(ExperimentalWindowApi::class)
 @RunWith(RobolectricTestRunner::class)
 class SplitAttributesCalculatorParamsTestingTest {
 
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/StubEmbeddingBackendTest.kt b/window/window-testing/src/test/java/androidx/window/testing/embedding/StubEmbeddingBackendTest.kt
index 537e4c1..4afd0ce 100644
--- a/window/window-testing/src/test/java/androidx/window/testing/embedding/StubEmbeddingBackendTest.kt
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/StubEmbeddingBackendTest.kt
@@ -33,7 +33,6 @@
 
     @Test
     fun removingSplitInfoListenerClearsListeners() {
-        val backend = StubEmbeddingBackend()
         val mockActivity = mock<Activity>()
         val mockCallback = mock<Consumer<List<SplitInfo>>>()
 
diff --git a/window/window-testing/src/test/java/androidx/window/testing/embedding/TestSplitInfo.kt b/window/window-testing/src/test/java/androidx/window/testing/embedding/TestSplitInfo.kt
new file mode 100644
index 0000000..8c261ef
--- /dev/null
+++ b/window/window-testing/src/test/java/androidx/window/testing/embedding/TestSplitInfo.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.window.testing.embedding
+
+import android.app.Activity
+import android.os.Binder
+import android.os.IBinder
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.embedding.ActivityStack
+import androidx.window.embedding.SplitAttributes
+import androidx.window.embedding.SplitInfo
+
+/**
+ * A convenience method to get a test [SplitInfo] with default values provided. With the default
+ * values it returns an empty [ActivityStack] for the primary and secondary stacks. The default
+ * [SplitAttributes] are for splitting equally and matching the locale layout.
+ *
+ * Note: This method should be used for testing local logic as opposed to end to end verification.
+ * End to end verification requires a device that supports Activity Embedding.
+ *
+ * @param primaryActivity the [Activity] for the primary container.
+ * @param secondaryActivity the [Activity] for the secondary container.
+ * @param splitAttributes the [SplitAttributes].
+ */
+@ExperimentalWindowApi
+fun TestSplitInfo(
+    primaryActivity: Activity,
+    secondaryActivity: Activity,
+    splitAttributes: SplitAttributes = SplitAttributes(),
+    token: IBinder = Binder()
+): SplitInfo {
+    val primaryActivityStack = TestActivityStack(primaryActivity, false)
+    val secondaryActivityStack = TestActivityStack(secondaryActivity, false)
+    return SplitInfo(primaryActivityStack, secondaryActivityStack, splitAttributes, token)
+}
+
+/**
+ * A convenience method to get a test [ActivityStack] with default values provided. With the default
+ * values, there will be a single [Activity] in the stack and it will be considered not empty.
+ *
+ * Note: This method should be used for testing local logic as opposed to end to end verification.
+ * End to end verification requires a device that supports Activity Embedding.
+ *
+ * @param testActivity an [Activity] that should be considered in the stack
+ * @param isEmpty states if the stack is empty or not. In practice an [ActivityStack] with a single
+ * [Activity] but [isEmpty] set to `false` means there is an [Activity] from outside the process
+ * in the stack.
+ */
+@ExperimentalWindowApi
+fun TestActivityStack(
+    testActivity: Activity,
+    isEmpty: Boolean = true,
+    token: IBinder = Binder()
+): ActivityStack {
+    return ActivityStack(
+        listOf(testActivity),
+        isEmpty,
+        token
+    )
+}
\ No newline at end of file
diff --git a/window/window-testing/src/test/resources/robolectric.properties b/window/window-testing/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..69fde47
--- /dev/null
+++ b/window/window-testing/src/test/resources/robolectric.properties
@@ -0,0 +1,3 @@
+# robolectric properties
+# Temporary until we update Robolectric to support API level 34.
+sdk=33
diff --git a/window/window/api/api_lint.ignore b/window/window/api/api_lint.ignore
index 24bf744..b709875 100644
--- a/window/window/api/api_lint.ignore
+++ b/window/window/api/api_lint.ignore
@@ -1,4 +1,8 @@
 // Baseline format: 1.0
+ContextFirst: androidx.window.embedding.ActivityEmbeddingOptions#setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context, androidx.window.embedding.ActivityStack) parameter #1:
+    Context is distinct, so it must be the first argument (method `setLaunchingActivityStack`)
+
+
 GetterSetterNames: field ActivityRule.alwaysExpand:
     Invalid name for boolean property `alwaysExpand`. Should start with one of `has`, `can`, `should`, `is`.
 GetterSetterNames: field SplitAttributesCalculatorParams.areDefaultConstraintsSatisfied:
diff --git a/window/window/api/current.txt b/window/window/api/current.txt
index 412af2b..e28ac35 100644
--- a/window/window/api/current.txt
+++ b/window/window/api/current.txt
@@ -5,6 +5,94 @@
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+    field public static final String PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED = "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+    field public static final String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
+    field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
+  }
+
+}
+
+package androidx.window.area {
+
+  public final class WindowAreaCapability {
+    method public androidx.window.area.WindowAreaCapability.Operation getOperation();
+    method public androidx.window.area.WindowAreaCapability.Status getStatus();
+    property public final androidx.window.area.WindowAreaCapability.Operation operation;
+    property public final androidx.window.area.WindowAreaCapability.Status status;
+  }
+
+  public static final class WindowAreaCapability.Operation {
+    field public static final androidx.window.area.WindowAreaCapability.Operation.Companion Companion;
+    field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_PRESENT_ON_AREA;
+    field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_TRANSFER_ACTIVITY_TO_AREA;
+  }
+
+  public static final class WindowAreaCapability.Operation.Companion {
+  }
+
+  public static final class WindowAreaCapability.Status {
+    field public static final androidx.window.area.WindowAreaCapability.Status.Companion Companion;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_ACTIVE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_AVAILABLE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNAVAILABLE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNSUPPORTED;
+  }
+
+  public static final class WindowAreaCapability.Status.Companion {
+  }
+
+  public interface WindowAreaController {
+    method public default static androidx.window.area.WindowAreaController getOrCreate();
+    method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> getWindowAreaInfos();
+    method public void presentContentOnWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaPresentationSessionCallback windowAreaPresentationSessionCallback);
+    method public void transferActivityToWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaSessionCallback windowAreaSessionCallback);
+    property public abstract kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> windowAreaInfos;
+    field public static final androidx.window.area.WindowAreaController.Companion Companion;
+  }
+
+  public static final class WindowAreaController.Companion {
+    method public androidx.window.area.WindowAreaController getOrCreate();
+  }
+
+  public final class WindowAreaInfo {
+    method public androidx.window.area.WindowAreaSession? getActiveSession(androidx.window.area.WindowAreaCapability.Operation operation);
+    method public androidx.window.area.WindowAreaCapability? getCapability(androidx.window.area.WindowAreaCapability.Operation operation);
+    method public androidx.window.layout.WindowMetrics getMetrics();
+    method public android.os.Binder getToken();
+    method public androidx.window.area.WindowAreaInfo.Type getType();
+    method public void setMetrics(androidx.window.layout.WindowMetrics);
+    property public final androidx.window.layout.WindowMetrics metrics;
+    property public final android.os.Binder token;
+    property public final androidx.window.area.WindowAreaInfo.Type type;
+  }
+
+  public static final class WindowAreaInfo.Type {
+    field public static final androidx.window.area.WindowAreaInfo.Type.Companion Companion;
+    field public static final androidx.window.area.WindowAreaInfo.Type TYPE_REAR_FACING;
+  }
+
+  public static final class WindowAreaInfo.Type.Companion {
+  }
+
+  public interface WindowAreaPresentationSessionCallback {
+    method public void onContainerVisibilityChanged(boolean isVisible);
+    method public void onSessionEnded(Throwable? t);
+    method public void onSessionStarted(androidx.window.area.WindowAreaSessionPresenter session);
+  }
+
+  public interface WindowAreaSession {
+    method public void close();
+  }
+
+  public interface WindowAreaSessionCallback {
+    method public void onSessionEnded(Throwable? t);
+    method public void onSessionStarted(androidx.window.area.WindowAreaSession session);
+  }
+
+  public interface WindowAreaSessionPresenter extends androidx.window.area.WindowAreaSession {
+    method public android.content.Context getContext();
+    method public void setContentView(android.view.View view);
+    property public abstract android.content.Context context;
   }
 
 }
@@ -19,8 +107,11 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
+    method @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -28,6 +119,12 @@
     method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
   }
 
+  public final class ActivityEmbeddingOptions {
+    method @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
+    method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+  }
+
   public final class ActivityFilter {
     ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
     method public android.content.ComponentName getComponentName();
@@ -132,7 +229,7 @@
     method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
   }
 
-  @androidx.window.core.ExperimentalWindowApi public final class SplitAttributesCalculatorParams {
+  public final class SplitAttributesCalculatorParams {
     method public boolean getAreDefaultConstraintsSatisfied();
     method public androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
     method public android.content.res.Configuration getParentConfiguration();
@@ -149,14 +246,18 @@
 
   public final class SplitController {
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
-    method @androidx.window.core.ExperimentalWindowApi public void clearSplitAttributesCalculator();
+    method public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @androidx.window.core.ExperimentalWindowApi public boolean isSplitAttributesCalculatorSupported();
+    method @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
+    method public boolean isSplitAttributesCalculatorSupported();
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public boolean isSplitSupported();
+    method @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
-    method @androidx.window.core.ExperimentalWindowApi public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/api/restricted_current.txt b/window/window/api/restricted_current.txt
index 412af2b..e28ac35 100644
--- a/window/window/api/restricted_current.txt
+++ b/window/window/api/restricted_current.txt
@@ -5,6 +5,94 @@
     field public static final androidx.window.WindowProperties INSTANCE;
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
     field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+    field public static final String PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED = "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+    field public static final String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
+    field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
+  }
+
+}
+
+package androidx.window.area {
+
+  public final class WindowAreaCapability {
+    method public androidx.window.area.WindowAreaCapability.Operation getOperation();
+    method public androidx.window.area.WindowAreaCapability.Status getStatus();
+    property public final androidx.window.area.WindowAreaCapability.Operation operation;
+    property public final androidx.window.area.WindowAreaCapability.Status status;
+  }
+
+  public static final class WindowAreaCapability.Operation {
+    field public static final androidx.window.area.WindowAreaCapability.Operation.Companion Companion;
+    field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_PRESENT_ON_AREA;
+    field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_TRANSFER_ACTIVITY_TO_AREA;
+  }
+
+  public static final class WindowAreaCapability.Operation.Companion {
+  }
+
+  public static final class WindowAreaCapability.Status {
+    field public static final androidx.window.area.WindowAreaCapability.Status.Companion Companion;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_ACTIVE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_AVAILABLE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNAVAILABLE;
+    field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNSUPPORTED;
+  }
+
+  public static final class WindowAreaCapability.Status.Companion {
+  }
+
+  public interface WindowAreaController {
+    method public default static androidx.window.area.WindowAreaController getOrCreate();
+    method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> getWindowAreaInfos();
+    method public void presentContentOnWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaPresentationSessionCallback windowAreaPresentationSessionCallback);
+    method public void transferActivityToWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaSessionCallback windowAreaSessionCallback);
+    property public abstract kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> windowAreaInfos;
+    field public static final androidx.window.area.WindowAreaController.Companion Companion;
+  }
+
+  public static final class WindowAreaController.Companion {
+    method public androidx.window.area.WindowAreaController getOrCreate();
+  }
+
+  public final class WindowAreaInfo {
+    method public androidx.window.area.WindowAreaSession? getActiveSession(androidx.window.area.WindowAreaCapability.Operation operation);
+    method public androidx.window.area.WindowAreaCapability? getCapability(androidx.window.area.WindowAreaCapability.Operation operation);
+    method public androidx.window.layout.WindowMetrics getMetrics();
+    method public android.os.Binder getToken();
+    method public androidx.window.area.WindowAreaInfo.Type getType();
+    method public void setMetrics(androidx.window.layout.WindowMetrics);
+    property public final androidx.window.layout.WindowMetrics metrics;
+    property public final android.os.Binder token;
+    property public final androidx.window.area.WindowAreaInfo.Type type;
+  }
+
+  public static final class WindowAreaInfo.Type {
+    field public static final androidx.window.area.WindowAreaInfo.Type.Companion Companion;
+    field public static final androidx.window.area.WindowAreaInfo.Type TYPE_REAR_FACING;
+  }
+
+  public static final class WindowAreaInfo.Type.Companion {
+  }
+
+  public interface WindowAreaPresentationSessionCallback {
+    method public void onContainerVisibilityChanged(boolean isVisible);
+    method public void onSessionEnded(Throwable? t);
+    method public void onSessionStarted(androidx.window.area.WindowAreaSessionPresenter session);
+  }
+
+  public interface WindowAreaSession {
+    method public void close();
+  }
+
+  public interface WindowAreaSessionCallback {
+    method public void onSessionEnded(Throwable? t);
+    method public void onSessionStarted(androidx.window.area.WindowAreaSession session);
+  }
+
+  public interface WindowAreaSessionPresenter extends androidx.window.area.WindowAreaSession {
+    method public android.content.Context getContext();
+    method public void setContentView(android.view.View view);
+    property public abstract android.content.Context context;
   }
 
 }
@@ -19,8 +107,11 @@
 package androidx.window.embedding {
 
   public final class ActivityEmbeddingController {
+    method @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+    method @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
     method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
     method public boolean isActivityEmbedded(android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
     field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
   }
 
@@ -28,6 +119,12 @@
     method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
   }
 
+  public final class ActivityEmbeddingOptions {
+    method @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
+    method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+  }
+
   public final class ActivityFilter {
     ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
     method public android.content.ComponentName getComponentName();
@@ -132,7 +229,7 @@
     method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
   }
 
-  @androidx.window.core.ExperimentalWindowApi public final class SplitAttributesCalculatorParams {
+  public final class SplitAttributesCalculatorParams {
     method public boolean getAreDefaultConstraintsSatisfied();
     method public androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
     method public android.content.res.Configuration getParentConfiguration();
@@ -149,14 +246,18 @@
 
   public final class SplitController {
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
-    method @androidx.window.core.ExperimentalWindowApi public void clearSplitAttributesCalculator();
+    method public void clearSplitAttributesCalculator();
     method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
     method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
-    method @androidx.window.core.ExperimentalWindowApi public boolean isSplitAttributesCalculatorSupported();
+    method @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+    method @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
+    method public boolean isSplitAttributesCalculatorSupported();
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public boolean isSplitSupported();
+    method @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
     method @Deprecated @androidx.window.core.ExperimentalWindowApi public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
-    method @androidx.window.core.ExperimentalWindowApi public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+    method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
     method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+    method @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
     property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
     field public static final androidx.window.embedding.SplitController.Companion Companion;
   }
diff --git a/window/window/build.gradle b/window/window/build.gradle
index b85bd94..e917b2e 100644
--- a/window/window/build.gradle
+++ b/window/window/build.gradle
@@ -50,7 +50,7 @@
     implementation("androidx.core:core:1.8.0")
 
     def extensions_core_version = "androidx.window.extensions.core:core:1.0.0"
-    def extensions_version = "androidx.window.extensions:extensions:1.1.0"
+    def extensions_version = project(":window:extensions:extensions")
     implementation(extensions_core_version)
     compileOnly(project(":window:sidecar:sidecar"))
     compileOnly(extensions_version)
@@ -63,7 +63,7 @@
     testImplementation(libs.mockitoCore4)
     testImplementation(libs.mockitoKotlin4)
     testImplementation(libs.kotlinCoroutinesTest)
-    testImplementation(extensions_core_version)
+    testImplementation(extensions_version)
     testImplementation(compileOnly(project(":window:sidecar:sidecar")))
     testImplementation(compileOnly(extensions_version))
 
diff --git a/window/window/lint-baseline.xml b/window/window/lint-baseline.xml
deleted file mode 100644
index 68a053a..0000000
--- a/window/window/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.1.0-alpha07">
-
-    <issue
-        id="BanHideAnnotation"
-        message="@hide is not allowed in Javadoc"
-        errorLine1="interface WindowAreaController {"
-        errorLine2="          ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/window/area/WindowAreaController.kt"/>
-    </issue>
-
-    <issue
-        id="BanHideAnnotation"
-        message="@hide is not allowed in Javadoc"
-        errorLine1="interface WindowAreaSession {"
-        errorLine2="          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/window/area/WindowAreaSession.kt"/>
-    </issue>
-
-    <issue
-        id="BanHideAnnotation"
-        message="@hide is not allowed in Javadoc"
-        errorLine1="interface WindowAreaSessionCallback {"
-        errorLine2="          ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/window/area/WindowAreaSessionCallback.kt"/>
-    </issue>
-
-    <issue
-        id="BanHideAnnotation"
-        message="@hide is not allowed in Javadoc"
-        errorLine1="class WindowAreaStatus private constructor(private val mDescription: String) {"
-        errorLine2="      ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/window/area/WindowAreaStatus.kt"/>
-    </issue>
-
-</issues>
diff --git a/window/window/proguard-rules.pro b/window/window/proguard-rules.pro
index 609e1cc1..b8cf236 100644
--- a/window/window/proguard-rules.pro
+++ b/window/window/proguard-rules.pro
@@ -22,4 +22,6 @@
  androidx.window.layout.adapter.sidecar.DistinctElementSidecarCallback {
   public *** onDeviceStateChanged(androidx.window.sidecar.SidecarDeviceState);
   public *** onWindowLayoutChanged(android.os.IBinder, androidx.window.sidecar.SidecarWindowLayoutInfo);
-}
\ No newline at end of file
+}
+# Required for window area API reflection guard
+-keep interface androidx.window.area.reflectionguard.* {*;}
\ No newline at end of file
diff --git a/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt b/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt
new file mode 100644
index 0000000..a7ab9cb
--- /dev/null
+++ b/window/window/samples/src/main/java/androidx.window.samples.embedding/FinishActivityStacksSamples.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.samples.embedding
+
+import android.app.Activity
+import androidx.annotation.Sampled
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.embedding.ActivityEmbeddingController
+import androidx.window.embedding.SplitController
+
+@OptIn(ExperimentalWindowApi::class)
+@Sampled
+suspend fun expandPrimaryContainer() {
+    SplitController.getInstance(primaryActivity).splitInfoList(primaryActivity)
+        .collect { splitInfoList ->
+            // Find all associated secondary ActivityStacks
+            val associatedSecondaryActivityStacks = splitInfoList
+                .mapTo(mutableSetOf()) { splitInfo -> splitInfo.secondaryActivityStack }
+            // Finish them all.
+            ActivityEmbeddingController.getInstance(primaryActivity)
+                .finishActivityStacks(associatedSecondaryActivityStacks)
+        }
+}
+
+val primaryActivity = Activity()
diff --git a/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt b/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
index c6a3607..e244fb9 100644
--- a/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
+++ b/window/window/samples/src/main/java/androidx.window.samples.embedding/SplitAttributesCalculatorSamples.kt
@@ -18,7 +18,6 @@
 
 import android.app.Application
 import androidx.annotation.Sampled
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.embedding.SplitAttributes
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.SPLIT_TYPE_EQUAL
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.SPLIT_TYPE_EXPAND
@@ -26,7 +25,6 @@
 import androidx.window.embedding.SplitController
 import androidx.window.layout.FoldingFeature
 
-@OptIn(ExperimentalWindowApi::class)
 @Sampled
 fun splitAttributesCalculatorSample() {
     SplitController.getInstance(context)
@@ -79,7 +77,6 @@
         }
 }
 
-@OptIn(ExperimentalWindowApi::class)
 @Sampled
 fun splitWithOrientations() {
     SplitController.getInstance(context)
@@ -107,7 +104,6 @@
         }
 }
 
-@OptIn(ExperimentalWindowApi::class)
 @Sampled
 fun expandContainersInPortrait() {
     SplitController.getInstance(context)
@@ -135,7 +131,6 @@
         }
 }
 
-@OptIn(ExperimentalWindowApi::class)
 @Sampled
 fun fallbackToExpandContainersForSplitTypeHinge() {
     SplitController.getInstance(context).setSplitAttributesCalculator { params ->
diff --git a/window/window/src/androidTest/AndroidManifest.xml b/window/window/src/androidTest/AndroidManifest.xml
index cd1d81e..e0d60f16 100644
--- a/window/window/src/androidTest/AndroidManifest.xml
+++ b/window/window/src/androidTest/AndroidManifest.xml
@@ -28,5 +28,19 @@
         <property
             android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
             android:value="true" />
+
+        <!-- Compat property -->
+        <property
+            android:name=
+                "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED"
+            android:value="false" />
+        <property
+            android:name=
+                "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE"
+            android:value="false" />
+        <property
+            android:name=
+                "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
+            android:value="false" />
     </application>
 </manifest>
diff --git a/window/window/src/androidTest/java/androidx/window/WindowPropertiesTest.kt b/window/window/src/androidTest/java/androidx/window/WindowPropertiesTest.kt
index 34eb50f..c7cf2f9 100644
--- a/window/window/src/androidTest/java/androidx/window/WindowPropertiesTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/WindowPropertiesTest.kt
@@ -21,6 +21,7 @@
 import android.os.Build
 import androidx.annotation.RequiresApi
 import androidx.test.ext.junit.rules.ActivityScenarioRule
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Assume.assumeTrue
 import org.junit.Rule
@@ -67,6 +68,25 @@
         }
     }
 
+    @Test
+    fun test_property_allow_ignoring_orientation_request_when_loop_detected() {
+        assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+            // No-op, but to suppress lint
+            return
+        }
+        activityRule.scenario.onActivity { activity ->
+            // Should be false as defined in AndroidManifest.xml
+            assertFalse(
+                getProperty(
+                    activity,
+                    WindowProperties
+                        .PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
+                )
+            )
+        }
+    }
+
     @RequiresApi(Build.VERSION_CODES.S)
     @Throws(PackageManager.NameNotFoundException::class)
     private fun getProperty(context: Context, propertyName: String): Boolean {
diff --git a/window/window/src/androidTest/java/androidx/window/area/SafeWindowAreaComponentProviderTest.kt b/window/window/src/androidTest/java/androidx/window/area/SafeWindowAreaComponentProviderTest.kt
new file mode 100644
index 0000000..50bb347
--- /dev/null
+++ b/window/window/src/androidTest/java/androidx/window/area/SafeWindowAreaComponentProviderTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.area
+
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.WindowExtensionsProvider
+import org.junit.Assert.assertNull
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+
+/**
+ * An integration test to verify that if [WindowExtensionsProvider] is present then
+ * [SafeWindowAreaComponentProvider.windowAreaComponent] will return a value. This can fail if
+ * the implementation of window:extensions:extensions does not have the expected API.
+ */
+class SafeWindowAreaComponentProviderTest {
+
+    /**
+     * Test that if [WindowExtensionsProvider] is available then
+     * [SafeWindowAreaComponentProvider.windowAreaComponent] returns a non-null value.
+     */
+    @Test
+    fun windowAreaComponentIsAvailable_ifProviderIsAvailable() {
+        assumeTrue(ExtensionsUtil.safeVendorApiLevel >= 2)
+        val loader = SafeWindowAreaComponentProvider::class.java.classLoader!!
+        val safeComponent = SafeWindowAreaComponentProvider(loader).windowAreaComponent
+
+        try {
+            val extensions = WindowExtensionsProvider.getWindowExtensions()
+            val actualComponent = extensions.windowAreaComponent
+            if (actualComponent == null) {
+                assertNull(safeComponent)
+            }
+            // TODO(b/267831038): verify upon each api level
+            // TODO(b/267708462): more reliable test for testing actual method matching
+        } catch (e: UnsupportedOperationException) {
+            // Invalid implementation of extensions
+            assertNull(safeComponent)
+        }
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt b/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt
index 963966d..f6f80437 100644
--- a/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/area/WindowAreaControllerImplTest.kt
@@ -16,29 +16,49 @@
 
 package androidx.window.area
 
-import android.annotation.TargetApi
 import android.app.Activity
+import android.content.Context
 import android.content.pm.ActivityInfo
+import android.os.Binder
 import android.os.Build
+import android.util.DisplayMetrics
+import android.view.View
+import android.widget.TextView
 import androidx.annotation.RequiresApi
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.window.TestActivity
-import androidx.window.TestConsumer
 import androidx.window.WindowTestUtils.Companion.assumeAtLeastVendorApiLevel
-import androidx.window.core.ExperimentalWindowApi
+import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_PRESENT_ON_AREA
+import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_TRANSFER_ACTIVITY_TO_AREA
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_AVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNAVAILABLE
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation
+import androidx.window.extensions.area.ExtensionWindowAreaStatus
 import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_ACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_INACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_ACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_AVAILABLE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_UNAVAILABLE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_UNSUPPORTED
 import androidx.window.extensions.core.util.function.Consumer
-import kotlin.test.assertFailsWith
+import androidx.window.layout.WindowMetricsCalculator
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.firstOrNull
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
+import org.junit.Assume.assumeTrue
 import org.junit.Rule
 import org.junit.Test
 
-@OptIn(ExperimentalCoroutinesApi::class, ExperimentalWindowApi::class)
+@OptIn(ExperimentalCoroutinesApi::class)
 class WindowAreaControllerImplTest {
 
     @get:Rule
@@ -47,55 +67,121 @@
 
     private val testScope = TestScope(UnconfinedTestDispatcher())
 
-    @TargetApi(Build.VERSION_CODES.N)
+    /**
+     * Tests that we can get a list of [WindowAreaInfo] objects with a type of
+     * [WindowAreaInfo.Type.TYPE_REAR_FACING]. Verifies that updating the status of features on
+     * device returns an updated [WindowAreaInfo] list.
+     */
+    @RequiresApi(Build.VERSION_CODES.Q)
     @Test
-    public fun testRearDisplayStatus(): Unit = testScope.runTest {
-        assumeAtLeastVendorApiLevel(2)
+    public fun testRearFacingWindowAreaInfoList(): Unit = testScope.runTest {
+        assumeTrue(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q)
+        assumeAtLeastVendorApiLevel(3)
         activityScenario.scenario.onActivity {
             val extensionComponent = FakeWindowAreaComponent()
-            val repo = WindowAreaControllerImpl(extensionComponent)
-            val collector = TestConsumer<WindowAreaStatus>()
-            extensionComponent
-                .updateStatusListeners(WindowAreaComponent.STATUS_UNAVAILABLE)
-            testScope.launch(Job()) {
-                repo.rearDisplayStatus().collect(collector::accept)
-            }
-            collector.assertValue(WindowAreaStatus.UNAVAILABLE)
-            extensionComponent
-                .updateStatusListeners(WindowAreaComponent.STATUS_AVAILABLE)
-            collector.assertValues(
-                WindowAreaStatus.UNAVAILABLE,
-                WindowAreaStatus.AVAILABLE
+            val controller = WindowAreaControllerImpl(
+                windowAreaComponent = extensionComponent,
+                vendorApiLevel = 3
             )
+            extensionComponent.currentRearDisplayStatus = STATUS_UNAVAILABLE
+            extensionComponent.currentRearDisplayPresentationStatus = STATUS_UNAVAILABLE
+            val collector = TestWindowAreaInfoListConsumer()
+            testScope.launch(Job()) {
+                controller.windowAreaInfos.collect(collector::accept)
+            }
+
+            val expectedAreaInfo = WindowAreaInfo(
+                metrics = WindowMetricsCalculator.fromDisplayMetrics(
+                    extensionComponent.rearDisplayMetrics
+                ),
+                type = WindowAreaInfo.Type.TYPE_REAR_FACING,
+                token = Binder(REAR_FACING_BINDER_DESCRIPTION),
+                windowAreaComponent = extensionComponent
+            )
+            val rearDisplayCapability = WindowAreaCapability(
+                OPERATION_TRANSFER_ACTIVITY_TO_AREA,
+                WINDOW_AREA_STATUS_UNAVAILABLE
+            )
+            val rearDisplayPresentationCapability = WindowAreaCapability(
+                OPERATION_PRESENT_ON_AREA,
+                WINDOW_AREA_STATUS_UNAVAILABLE
+            )
+            expectedAreaInfo.capabilityMap[OPERATION_TRANSFER_ACTIVITY_TO_AREA] =
+                rearDisplayCapability
+            expectedAreaInfo.capabilityMap[OPERATION_PRESENT_ON_AREA] =
+                rearDisplayPresentationCapability
+
+            assertEquals(listOf(expectedAreaInfo), collector.values[collector.values.size - 1])
+
+            extensionComponent
+                .updateRearDisplayStatusListeners(STATUS_AVAILABLE)
+
+            val updatedRearDisplayCapability = WindowAreaCapability(
+                OPERATION_TRANSFER_ACTIVITY_TO_AREA,
+                WINDOW_AREA_STATUS_AVAILABLE
+            )
+            expectedAreaInfo.capabilityMap[OPERATION_TRANSFER_ACTIVITY_TO_AREA] =
+                updatedRearDisplayCapability
+
+            assertEquals(listOf(expectedAreaInfo), collector.values[collector.values.size - 1])
+
+            // Update the presentation capability status and verify that only one window area
+            // info is still returned
+            extensionComponent.updateRearDisplayPresentationStatusListeners(STATUS_AVAILABLE)
+
+            val updatedRearDisplayPresentationCapability = WindowAreaCapability(
+                OPERATION_PRESENT_ON_AREA,
+                WINDOW_AREA_STATUS_AVAILABLE
+            )
+            expectedAreaInfo.capabilityMap[OPERATION_PRESENT_ON_AREA] =
+                updatedRearDisplayPresentationCapability
+
+            assertEquals(listOf(expectedAreaInfo), collector.values[collector.values.size - 1])
         }
     }
 
     @Test
-    public fun testRearDisplayStatusNullComponent(): Unit = testScope.runTest {
+    public fun testWindowAreaInfoListNullComponent(): Unit = testScope.runTest {
         activityScenario.scenario.onActivity {
-            val repo = EmptyWindowAreaControllerImpl()
-            val collector = TestConsumer<WindowAreaStatus>()
+            val controller = EmptyWindowAreaControllerImpl()
+            val collector = TestWindowAreaInfoListConsumer()
             testScope.launch(Job()) {
-                repo.rearDisplayStatus().collect(collector::accept)
+                controller.windowAreaInfos.collect(collector::accept)
             }
-            collector.assertValue(WindowAreaStatus.UNSUPPORTED)
+            assertTrue(collector.values.size == 1)
+            assertEquals(listOf(), collector.values[0])
         }
     }
 
     /**
-     * Tests the rear display mode flow works as expected. Tests the flow
+     * Tests the transfer to rear facing window area flow. Tests the flow
      * through WindowAreaControllerImpl with a fake extension. This fake extension
-     * changes the orientation of the activity to landscape when rear display mode is enabled
-     * and then returns it back to portrait when it's disabled.
+     * changes the orientation of the activity to landscape to simulate a configuration change that
+     * would occur when transferring to the rear facing window area and then returns it back to
+     * portrait when it's disabled.
      */
-    @TargetApi(Build.VERSION_CODES.N)
+    @RequiresApi(Build.VERSION_CODES.Q)
     @Test
-    public fun testRearDisplayMode(): Unit = testScope.runTest {
-        assumeAtLeastVendorApiLevel(2)
+    public fun testTransferToRearFacingWindowArea(): Unit = testScope.runTest {
+        assumeAtLeastVendorApiLevel(3)
         val extensions = FakeWindowAreaComponent()
-        val repo = WindowAreaControllerImpl(extensions)
-        extensions.currentStatus = WindowAreaComponent.STATUS_AVAILABLE
+        val controller = WindowAreaControllerImpl(
+            windowAreaComponent = extensions,
+            vendorApiLevel = 3
+        )
+        extensions.currentRearDisplayStatus = STATUS_AVAILABLE
         val callback = TestWindowAreaSessionCallback()
+        var windowAreaInfo: WindowAreaInfo? = null
+        testScope.launch(Job()) {
+            windowAreaInfo = controller.windowAreaInfos.firstOrNull()
+                ?.firstOrNull { it.type == WindowAreaInfo.Type.TYPE_REAR_FACING }
+        }
+        assertNotNull(windowAreaInfo)
+        assertEquals(
+            windowAreaInfo!!.getCapability(OPERATION_TRANSFER_ACTIVITY_TO_AREA)?.status,
+            WINDOW_AREA_STATUS_AVAILABLE
+        )
+
         activityScenario.scenario.onActivity { testActivity ->
             testActivity.resetLayoutCounter()
             testActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
@@ -105,7 +191,12 @@
         activityScenario.scenario.onActivity { testActivity ->
             assert(testActivity.requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
             testActivity.resetLayoutCounter()
-            repo.rearDisplayMode(testActivity, Runnable::run, callback)
+            controller.transferActivityToWindowArea(
+                windowAreaInfo!!.token,
+                testActivity,
+                Runnable::run,
+                callback
+            )
         }
 
         activityScenario.scenario.onActivity { testActivity ->
@@ -120,84 +211,255 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.N)
+    @RequiresApi(Build.VERSION_CODES.Q)
     @Test
-    public fun testRearDisplayModeReturnsError(): Unit = testScope.runTest {
-        assumeAtLeastVendorApiLevel(2)
-        val extensionComponent = FakeWindowAreaComponent()
-        extensionComponent.currentStatus = WindowAreaComponent.STATUS_UNAVAILABLE
-        val repo = WindowAreaControllerImpl(extensionComponent)
+    public fun testTransferRearDisplayReturnsError_statusUnavailable(): Unit = testScope.runTest {
+        testTransferRearDisplayReturnsError(STATUS_UNAVAILABLE)
+    }
+
+    @RequiresApi(Build.VERSION_CODES.Q)
+    @Test
+    public fun testTransferRearDisplayReturnsError_statusActive(): Unit = testScope.runTest {
+        testTransferRearDisplayReturnsError(STATUS_ACTIVE)
+    }
+
+    @RequiresApi(Build.VERSION_CODES.Q)
+    private fun testTransferRearDisplayReturnsError(
+        initialState: @WindowAreaComponent.WindowAreaStatus Int
+    ) {
+        assumeAtLeastVendorApiLevel(3)
+        val extensions = FakeWindowAreaComponent()
+        val controller = WindowAreaControllerImpl(
+            windowAreaComponent = extensions,
+            vendorApiLevel = 2
+        )
+        extensions.currentRearDisplayStatus = initialState
         val callback = TestWindowAreaSessionCallback()
+        var windowAreaInfo: WindowAreaInfo? = null
+        testScope.launch(Job()) {
+            windowAreaInfo = controller.windowAreaInfos.firstOrNull()
+                ?.firstOrNull { it.type == WindowAreaInfo.Type.TYPE_REAR_FACING }
+        }
+        assertNotNull(windowAreaInfo)
+        assertEquals(
+            windowAreaInfo!!.getCapability(OPERATION_TRANSFER_ACTIVITY_TO_AREA)?.status,
+            WindowAreaAdapter.translate(initialState)
+        )
+
         activityScenario.scenario.onActivity { testActivity ->
-            assertFailsWith(
-                exceptionClass = UnsupportedOperationException::class,
-                block = { repo.rearDisplayMode(testActivity, Runnable::run, callback) }
+            controller.transferActivityToWindowArea(
+                windowAreaInfo!!.token,
+                testActivity,
+                Runnable::run,
+                callback
             )
+            assertNotNull(callback.error)
+            assertNull(callback.currentSession)
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.N)
+    /**
+     * Tests the presentation flow on to a rear facing display works as expected. The
+     * [WindowAreaPresentationSessionCallback] provided to
+     * [WindowAreaControllerImpl.presentContentOnWindowArea] should receive a
+     * [WindowAreaSessionPresenter] when the session is active, and be notified that the [View]
+     * provided through [WindowAreaSessionPresenter.setContentView] is visible when inflated.
+     *
+     * Tests the flow through WindowAreaControllerImpl with a fake extension component.
+     */
+    @RequiresApi(Build.VERSION_CODES.Q)
     @Test
-    public fun testRearDisplayModeNullComponent(): Unit = testScope.runTest {
-        val repo = EmptyWindowAreaControllerImpl()
-        val callback = TestWindowAreaSessionCallback()
+    public fun testPresentRearDisplayArea(): Unit = testScope.runTest {
+        assumeAtLeastVendorApiLevel(3)
+        val extensions = FakeWindowAreaComponent()
+        val controller = WindowAreaControllerImpl(
+            windowAreaComponent = extensions,
+            vendorApiLevel = 3
+        )
+        var windowAreaInfo: WindowAreaInfo? = null
+        extensions.updateRearDisplayStatusListeners(STATUS_AVAILABLE)
+        extensions.updateRearDisplayPresentationStatusListeners(STATUS_AVAILABLE)
+        testScope.launch(Job()) {
+            windowAreaInfo = controller.windowAreaInfos.firstOrNull()
+                ?.firstOrNull { it.type == WindowAreaInfo.Type.TYPE_REAR_FACING }
+        }
+        assertNotNull(windowAreaInfo)
+        assertTrue {
+            windowAreaInfo!!
+                .getCapability(OPERATION_PRESENT_ON_AREA)?.status ==
+                WINDOW_AREA_STATUS_AVAILABLE
+        }
+
+        val callback = TestWindowAreaPresentationSessionCallback()
         activityScenario.scenario.onActivity { testActivity ->
-            assertFailsWith(
-                exceptionClass = UnsupportedOperationException::class,
-                block = { repo.rearDisplayMode(testActivity, Runnable::run, callback) }
+            controller.presentContentOnWindowArea(
+                windowAreaInfo!!.token,
+                testActivity,
+                Runnable::run,
+                callback
             )
+            assert(callback.sessionActive)
+            assert(!callback.contentVisible)
+
+            callback.presentation?.setContentView(TextView(testActivity))
+            assert(callback.contentVisible)
+            assert(callback.sessionActive)
+
+            callback.presentation?.close()
+            assert(!callback.contentVisible)
+            assert(!callback.sessionActive)
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.Q)
+    @Test
+    public fun testRearDisplayPresentationModeSessionEndedError(): Unit = testScope.runTest {
+        assumeAtLeastVendorApiLevel(3)
+        val extensionComponent = FakeWindowAreaComponent()
+        val controller = WindowAreaControllerImpl(
+            windowAreaComponent = extensionComponent,
+            vendorApiLevel = 3
+        )
+        var windowAreaInfo: WindowAreaInfo? = null
+        extensionComponent.updateRearDisplayStatusListeners(STATUS_AVAILABLE)
+        extensionComponent.updateRearDisplayPresentationStatusListeners(STATUS_UNAVAILABLE)
+        testScope.launch(Job()) {
+            windowAreaInfo = controller.windowAreaInfos.firstOrNull()
+                ?.firstOrNull { it.type == WindowAreaInfo.Type.TYPE_REAR_FACING }
+        }
+        assertNotNull(windowAreaInfo)
+        assertTrue {
+            windowAreaInfo!!
+                .getCapability(OPERATION_PRESENT_ON_AREA)?.status ==
+                WINDOW_AREA_STATUS_UNAVAILABLE
+        }
+
+        val callback = TestWindowAreaPresentationSessionCallback()
+        activityScenario.scenario.onActivity { testActivity ->
+            controller.presentContentOnWindowArea(
+                windowAreaInfo!!.token,
+                testActivity,
+                Runnable::run,
+                callback
+            )
+            assert(!callback.sessionActive)
+            assert(callback.sessionError != null)
+            assert(callback.sessionError is IllegalStateException)
+        }
+    }
+
+    private class TestWindowAreaInfoListConsumer : Consumer<List<WindowAreaInfo>> {
+
+        val values: MutableList<List<WindowAreaInfo>> = mutableListOf()
+        override fun accept(infos: List<WindowAreaInfo>) {
+            values.add(infos)
         }
     }
 
     private class FakeWindowAreaComponent : WindowAreaComponent {
-        val statusListeners = mutableListOf<Consumer<Int>>()
-        var currentStatus = WindowAreaComponent.STATUS_UNSUPPORTED
-        var testActivity: Activity? = null
-        var sessionConsumer: Consumer<Int>? = null
+        val rearDisplayStatusListeners = mutableListOf<Consumer<Int>>()
+        val rearDisplayPresentationStatusListeners =
+            mutableListOf<Consumer<ExtensionWindowAreaStatus>>()
+        var currentRearDisplayStatus = STATUS_UNSUPPORTED
+        var currentRearDisplayPresentationStatus = STATUS_UNSUPPORTED
 
-        @RequiresApi(Build.VERSION_CODES.N)
+        var testActivity: Activity? = null
+        var rearDisplaySessionConsumer: Consumer<Int>? = null
+        var rearDisplayPresentationSessionConsumer: Consumer<Int>? = null
+
         override fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
-            statusListeners.add(consumer)
-            consumer.accept(currentStatus)
+            rearDisplayStatusListeners.add(consumer)
+            consumer.accept(currentRearDisplayStatus)
         }
 
         override fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
-            statusListeners.remove(consumer)
+            rearDisplayStatusListeners.remove(consumer)
+        }
+
+        override fun addRearDisplayPresentationStatusListener(
+            consumer: Consumer<ExtensionWindowAreaStatus>
+        ) {
+            rearDisplayPresentationStatusListeners.add(consumer)
+            consumer.accept(TestExtensionWindowAreaStatus(currentRearDisplayPresentationStatus))
+        }
+
+        override fun removeRearDisplayPresentationStatusListener(
+            consumer: Consumer<ExtensionWindowAreaStatus>
+        ) {
+            rearDisplayPresentationStatusListeners.remove(consumer)
         }
 
         // Fake WindowAreaComponent will change the orientation of the activity to signal
         // entering rear display mode, as well as ending the session
-        @RequiresApi(Build.VERSION_CODES.N)
         override fun startRearDisplaySession(
             activity: Activity,
             rearDisplaySessionConsumer: Consumer<Int>
         ) {
-            if (currentStatus != WindowAreaComponent.STATUS_AVAILABLE) {
-                throw UnsupportedOperationException("Rear Display mode cannot be enabled currently")
+            if (currentRearDisplayStatus != STATUS_AVAILABLE) {
+                rearDisplaySessionConsumer.accept(SESSION_STATE_INACTIVE)
             }
             testActivity = activity
-            sessionConsumer = rearDisplaySessionConsumer
+            this.rearDisplaySessionConsumer = rearDisplaySessionConsumer
             testActivity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
             rearDisplaySessionConsumer.accept(WindowAreaComponent.SESSION_STATE_ACTIVE)
         }
 
-        @RequiresApi(Build.VERSION_CODES.N)
         override fun endRearDisplaySession() {
             testActivity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
-            sessionConsumer?.accept(WindowAreaComponent.SESSION_STATE_INACTIVE)
+            rearDisplaySessionConsumer?.accept(SESSION_STATE_INACTIVE)
         }
 
-        @RequiresApi(Build.VERSION_CODES.N)
-        fun updateStatusListeners(newStatus: Int) {
-            currentStatus = newStatus
-            for (consumer in statusListeners) {
-                consumer.accept(currentStatus)
+        override fun startRearDisplayPresentationSession(
+            activity: Activity,
+            consumer: Consumer<Int>
+        ) {
+            if (currentRearDisplayPresentationStatus != STATUS_AVAILABLE) {
+                consumer.accept(SESSION_STATE_INACTIVE)
+                return
+            }
+            testActivity = activity
+            rearDisplayPresentationSessionConsumer = consumer
+            consumer.accept(SESSION_STATE_ACTIVE)
+        }
+
+        override fun endRearDisplayPresentationSession() {
+            rearDisplayPresentationSessionConsumer?.accept(
+                WindowAreaComponent.SESSION_STATE_ACTIVE)
+            rearDisplayPresentationSessionConsumer?.accept(
+                WindowAreaComponent.SESSION_STATE_INACTIVE)
+        }
+
+        override fun getRearDisplayPresentation(): ExtensionWindowAreaPresentation? {
+            return TestExtensionWindowAreaPresentation(
+                testActivity!!,
+                rearDisplayPresentationSessionConsumer!!
+            )
+        }
+
+        override fun getRearDisplayMetrics(): DisplayMetrics {
+            return DisplayMetrics().apply {
+                widthPixels = 1080
+                heightPixels = 1080
+                densityDpi = 240
+            }
+        }
+
+        fun updateRearDisplayStatusListeners(newStatus: Int) {
+            currentRearDisplayStatus = newStatus
+            for (consumer in rearDisplayStatusListeners) {
+                consumer.accept(currentRearDisplayStatus)
+            }
+        }
+
+        fun updateRearDisplayPresentationStatusListeners(newStatus: Int) {
+            currentRearDisplayPresentationStatus = newStatus
+            for (consumer in rearDisplayPresentationStatusListeners) {
+                consumer.accept(TestExtensionWindowAreaStatus(currentRearDisplayPresentationStatus))
             }
         }
     }
 
     private class TestWindowAreaSessionCallback : WindowAreaSessionCallback {
-
         var currentSession: WindowAreaSession? = null
         var error: Throwable? = null
 
@@ -205,10 +467,65 @@
             currentSession = session
         }
 
-        override fun onSessionEnded() {
+        override fun onSessionEnded(t: Throwable?) {
+            error = t
             currentSession = null
         }
 
         fun endSession() = currentSession?.close()
     }
-}
+
+    private class TestWindowAreaPresentationSessionCallback :
+        WindowAreaPresentationSessionCallback {
+        var sessionActive: Boolean = false
+        var contentVisible: Boolean = false
+        var presentation: WindowAreaSessionPresenter? = null
+        var sessionError: Throwable? = null
+        override fun onSessionStarted(session: WindowAreaSessionPresenter) {
+            sessionActive = true
+            presentation = session
+        }
+
+        override fun onSessionEnded(t: Throwable?) {
+            presentation = null
+            sessionActive = false
+            sessionError = t
+        }
+
+        override fun onContainerVisibilityChanged(isVisible: Boolean) {
+            contentVisible = isVisible
+        }
+    }
+
+    private class TestExtensionWindowAreaStatus(private val status: Int) :
+        ExtensionWindowAreaStatus {
+        override fun getWindowAreaStatus(): Int {
+            return status
+        }
+
+        override fun getWindowAreaDisplayMetrics(): DisplayMetrics {
+            return DisplayMetrics().apply {
+                widthPixels = 1080
+                heightPixels = 1080
+                densityDpi = 240
+            }
+        }
+    }
+
+    private class TestExtensionWindowAreaPresentation(
+        private val activity: Activity,
+        private val sessionConsumer: Consumer<Int>
+    ) : ExtensionWindowAreaPresentation {
+        override fun getPresentationContext(): Context {
+            return activity
+        }
+
+        override fun setPresentationView(view: View) {
+            sessionConsumer.accept(WindowAreaComponent.SESSION_STATE_CONTENT_VISIBLE)
+        }
+    }
+
+    companion object {
+        private const val REAR_FACING_BINDER_DESCRIPTION = "TEST_WINDOW_AREA_REAR_FACING"
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/androidTest/java/androidx/window/area/reflectionguard/WindowAreaComponentValidatorTest.kt b/window/window/src/androidTest/java/androidx/window/area/reflectionguard/WindowAreaComponentValidatorTest.kt
new file mode 100644
index 0000000..532fd65
--- /dev/null
+++ b/window/window/src/androidTest/java/androidx/window/area/reflectionguard/WindowAreaComponentValidatorTest.kt
@@ -0,0 +1,265 @@
+/*
+ * 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.window.area.reflectionguard
+
+import android.app.Activity
+import android.content.Context
+import android.util.DisplayMetrics
+import android.view.View
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation
+import androidx.window.extensions.area.ExtensionWindowAreaStatus
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.extensions.core.util.function.Consumer
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.Test
+
+/**
+ * Unit test for [WindowAreaComponentValidator]
+ */
+class WindowAreaComponentValidatorTest {
+
+    /**
+     * Test that validator returns true if the component fully implements [WindowAreaComponent]
+     */
+    @Test
+    fun isWindowAreaComponentValid_fullImplementation() {
+        assertTrue(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                WindowAreaComponentFullImplementation::class.java, 2))
+        assertTrue(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                WindowAreaComponentFullImplementation::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns correct results for API Level 2 [WindowAreaComponent]
+     * implementation.
+     */
+    @Test
+    fun isWindowAreaComponentValid_apiLevel2() {
+        assertTrue(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                WindowAreaComponentApiV2Implementation::class.java, 2))
+        assertFalse(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                IncompleteWindowAreaComponentApiV2Implementation::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns correct results for API Level 3 [WindowAreaComponent]
+     * implementation.
+     */
+    @Test
+    fun isWindowAreaComponentValid_apiLevel3() {
+        assertTrue(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                WindowAreaComponentApiV3Implementation::class.java, 2))
+        assertTrue(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                WindowAreaComponentApiV3Implementation::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns false if the component implementation is incomplete
+     */
+    @Test
+    fun isWindowAreaComponentValid_falseIfIncompleteImplementation() {
+        assertFalse(
+            WindowAreaComponentValidator.isWindowAreaComponentValid(
+                IncompleteWindowAreaComponentApiV2Implementation::class.java, 2))
+    }
+
+    /**
+     * Test that validator returns true if the [ExtensionWindowAreaStatus] is valid
+     */
+    @Test
+    fun isExtensionWindowAreaStatusValid_trueIfValid() {
+        assertTrue(
+            WindowAreaComponentValidator.isExtensionWindowAreaStatusValid(
+                ValidExtensionWindowAreaStatus::class.java, 2))
+        assertTrue(
+            WindowAreaComponentValidator.isExtensionWindowAreaStatusValid(
+                ValidExtensionWindowAreaStatus::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns false if the [ExtensionWindowAreaStatus] is incomplete
+     */
+    @Test
+    fun isExtensionWindowAreaStatusValid_falseIfIncomplete() {
+        assertFalse(
+            WindowAreaComponentValidator.isExtensionWindowAreaStatusValid(
+                IncompleteExtensionWindowAreaStatus::class.java, 2))
+        assertFalse(
+            WindowAreaComponentValidator.isExtensionWindowAreaStatusValid(
+                IncompleteExtensionWindowAreaStatus::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns true if the [ExtensionWindowAreaPresentation] is valid
+     */
+    @Test
+    fun isExtensionWindowAreaPresentationValid_trueIfValid() {
+        assertTrue(
+            WindowAreaComponentValidator.isExtensionWindowAreaPresentationValid(
+                ValidExtensionWindowAreaPresentation::class.java, 3))
+    }
+
+    /**
+     * Test that validator returns false if the [ExtensionWindowAreaPresentation] is incomplete
+     */
+    @Test
+    fun isExtensionWindowAreaPresentationValid_falseIfIncomplete() {
+        assertFalse(
+            WindowAreaComponentValidator.isExtensionWindowAreaPresentationValid(
+                IncompleteExtensionWindowAreaPresentation::class.java, 3))
+    }
+
+    private class WindowAreaComponentFullImplementation : WindowAreaComponent {
+        override fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun startRearDisplaySession(activity: Activity, consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun endRearDisplaySession() {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun getRearDisplayMetrics(): DisplayMetrics {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class WindowAreaComponentApiV2Implementation : WindowAreaComponentApi2Requirements {
+        override fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun startRearDisplaySession(activity: Activity, consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun endRearDisplaySession() {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class WindowAreaComponentApiV3Implementation : WindowAreaComponentApi3Requirements {
+        override fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun startRearDisplaySession(activity: Activity, consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun endRearDisplaySession() {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun addRearDisplayPresentationStatusListener(
+            consumer: Consumer<ExtensionWindowAreaStatus>
+        ) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun removeRearDisplayPresentationStatusListener(
+            consumer: Consumer<ExtensionWindowAreaStatus>
+        ) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun startRearDisplayPresentationSession(
+            activity: Activity,
+            consumer: Consumer<Int>
+        ) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun endRearDisplayPresentationSession() {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun getRearDisplayPresentation(): ExtensionWindowAreaPresentation? {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun getRearDisplayMetrics(): DisplayMetrics {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class IncompleteWindowAreaComponentApiV2Implementation {
+        @Suppress("UNUSED_PARAMETER")
+        fun addRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+
+        @Suppress("UNUSED_PARAMETER")
+        fun removeRearDisplayStatusListener(consumer: Consumer<Int>) {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class ValidExtensionWindowAreaPresentation : ExtensionWindowAreaPresentation {
+        override fun getPresentationContext(): Context {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun setPresentationView(view: View) {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class IncompleteExtensionWindowAreaPresentation {
+        fun getPresentationContext(): Context {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class ValidExtensionWindowAreaStatus : ExtensionWindowAreaStatus {
+        override fun getWindowAreaStatus(): Int {
+            throw NotImplementedError("Not implemented")
+        }
+
+        override fun getWindowAreaDisplayMetrics(): DisplayMetrics {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+
+    private class IncompleteExtensionWindowAreaStatus {
+        fun getWindowAreaStatus(): Int {
+            throw NotImplementedError("Not implemented")
+        }
+    }
+}
diff --git a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
index 6d76005..5aaf0aa 100644
--- a/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/embedding/EmbeddingAdapterTest.kt
@@ -17,9 +17,13 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.os.Binder
+import android.os.IBinder
 import androidx.window.WindowTestUtils
 import androidx.window.core.ExtensionsUtil
 import androidx.window.core.PredicateAdapter
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_ACTIVITY_STACK_TOKEN
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_SPLIT_INFO_TOKEN
 import androidx.window.embedding.SplitAttributes.SplitType
 import androidx.window.embedding.SplitAttributes.SplitType.Companion.SPLIT_TYPE_HINGE
 import androidx.window.extensions.WindowExtensions
@@ -55,12 +59,13 @@
             OEMSplitAttributes.Builder().build(),
         )
         val expectedSplitInfo = SplitInfo(
-            ActivityStack(ArrayList(), isEmpty = true),
-            ActivityStack(ArrayList(), isEmpty = true),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
             SplitAttributes.Builder()
                 .setSplitType(SplitType.SPLIT_TYPE_EQUAL)
                 .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
-                .build()
+                .build(),
+            INVALID_SPLIT_INFO_TOKEN,
         )
         assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
     }
@@ -77,12 +82,13 @@
                 .build(),
         )
         val expectedSplitInfo = SplitInfo(
-            ActivityStack(ArrayList(), isEmpty = true),
-            ActivityStack(ArrayList(), isEmpty = true),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
             SplitAttributes.Builder()
                 .setSplitType(SplitType.SPLIT_TYPE_EXPAND)
                 .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
-                .build()
+                .build(),
+            INVALID_SPLIT_INFO_TOKEN,
         )
         assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
     }
@@ -101,13 +107,14 @@
         }
 
         val expectedSplitInfo = SplitInfo(
-            ActivityStack(ArrayList(), isEmpty = true),
-            ActivityStack(ArrayList(), isEmpty = true),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
             SplitAttributes.Builder()
                 .setSplitType(SplitType.ratio(expectedSplitRatio))
                 // OEMSplitInfo with Vendor API level 1 doesn't provide layoutDirection.
                 .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
-                .build()
+                .build(),
+            INVALID_SPLIT_INFO_TOKEN,
         )
         assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
     }
@@ -125,12 +132,39 @@
                 .build(),
         )
         val expectedSplitInfo = SplitInfo(
-            ActivityStack(ArrayList(), isEmpty = true),
-            ActivityStack(ArrayList(), isEmpty = true),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
+            ActivityStack(ArrayList(), isEmpty = true, INVALID_ACTIVITY_STACK_TOKEN),
             SplitAttributes.Builder()
                 .setSplitType(SPLIT_TYPE_HINGE)
                 .setLayoutDirection(SplitAttributes.LayoutDirection.TOP_TO_BOTTOM)
-                .build()
+                .build(),
+            INVALID_SPLIT_INFO_TOKEN,
+        )
+        assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
+    }
+
+    @Test
+    fun testTranslateSplitInfoWithApiLevel3() {
+        WindowTestUtils.assumeAtLeastVendorApiLevel(WindowExtensions.VENDOR_API_LEVEL_3)
+        val testStackToken = Binder()
+        val testSplitInfoToken = Binder()
+        val oemSplitInfo = createTestOEMSplitInfo(
+            createTestOEMActivityStack(ArrayList(), true, testStackToken),
+            createTestOEMActivityStack(ArrayList(), true, testStackToken),
+            OEMSplitAttributes.Builder()
+                .setSplitType(OEMSplitAttributes.SplitType.HingeSplitType(RatioSplitType(0.5f)))
+                .setLayoutDirection(TOP_TO_BOTTOM)
+                .build(),
+            testSplitInfoToken,
+        )
+        val expectedSplitInfo = SplitInfo(
+            ActivityStack(ArrayList(), isEmpty = true, testStackToken),
+            ActivityStack(ArrayList(), isEmpty = true, testStackToken),
+            SplitAttributes.Builder()
+                .setSplitType(SPLIT_TYPE_HINGE)
+                .setLayoutDirection(SplitAttributes.LayoutDirection.TOP_TO_BOTTOM)
+                .build(),
+            testSplitInfoToken,
         )
         assertEquals(listOf(expectedSplitInfo), adapter.translate(listOf(oemSplitInfo)))
     }
@@ -139,6 +173,7 @@
         testPrimaryActivityStack: OEMActivityStack,
         testSecondaryActivityStack: OEMActivityStack,
         testSplitAttributes: OEMSplitAttributes,
+        testToken: IBinder = INVALID_SPLIT_INFO_TOKEN,
     ): OEMSplitInfo {
         return mock<OEMSplitInfo>().apply {
             whenever(primaryActivityStack).thenReturn(testPrimaryActivityStack)
@@ -146,16 +181,23 @@
             if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_2) {
                 whenever(splitAttributes).thenReturn(testSplitAttributes)
             }
+            if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3) {
+                whenever(token).thenReturn(testToken)
+            }
         }
     }
 
     private fun createTestOEMActivityStack(
         testActivities: List<Activity>,
         testIsEmpty: Boolean,
+        testToken: IBinder = INVALID_ACTIVITY_STACK_TOKEN,
     ): OEMActivityStack {
         return mock<OEMActivityStack>().apply {
             whenever(activities).thenReturn(testActivities)
             whenever(isEmpty).thenReturn(testIsEmpty)
+            if (ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3) {
+                whenever(token).thenReturn(testToken)
+            }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/window/window/src/main/java/androidx/window/SafeWindowExtensionsProvider.kt b/window/window/src/main/java/androidx/window/SafeWindowExtensionsProvider.kt
index 2aa82f4..c33b215 100644
--- a/window/window/src/main/java/androidx/window/SafeWindowExtensionsProvider.kt
+++ b/window/window/src/main/java/androidx/window/SafeWindowExtensionsProvider.kt
@@ -16,12 +16,26 @@
 
 package androidx.window
 
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.WindowExtensionsProvider
 import androidx.window.reflection.ReflectionUtils
 import androidx.window.reflection.ReflectionUtils.doesReturn
 import androidx.window.reflection.ReflectionUtils.isPublic
 import androidx.window.reflection.WindowExtensionsConstants
 
 internal class SafeWindowExtensionsProvider(private val loader: ClassLoader) {
+
+    val windowExtensions: WindowExtensions?
+        get() {
+            return try {
+                if (isWindowExtensionsPresent() && isWindowExtensionsValid()) {
+                    WindowExtensionsProvider.getWindowExtensions()
+                } else null
+            } catch (e: Exception) {
+                null
+            }
+        }
+
     internal val windowExtensionsClass: Class<*>
         get() {
             return loader.loadClass(WindowExtensionsConstants.WINDOW_EXTENSIONS_CLASS)
diff --git a/window/window/src/main/java/androidx/window/WindowProperties.kt b/window/window/src/main/java/androidx/window/WindowProperties.kt
index 156652f..6f73640 100644
--- a/window/window/src/main/java/androidx/window/WindowProperties.kt
+++ b/window/window/src/main/java/androidx/window/WindowProperties.kt
@@ -87,4 +87,99 @@
      */
     const val PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED =
         "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
+
+    /**
+     * Application level
+     * [PackageManager][android.content.pm.PackageManager.Property] tag
+     * for an app to inform the system that the app can be opted-out from the compatibility
+     * treatment that avoids [android.app.Activity.setRequestedOrientation] loops. The loop
+     * can be trigerred when ignoreOrientationRequest display setting is
+     * enabled on the device (enables compatibility mode for fixed orientation,
+     * see [Enhanced letterboxing](https://developer.android.com/guide/practices/enhanced-letterboxing)
+     * for more details). or by the landscape natural orientation of the device.
+     *
+     *
+     * The system could ignore [android.app.Activity.setRequestedOrientation]
+     * call from an app if both of the following conditions are true:
+     *  * Activity has requested orientation more than 2 times within 1-second timer
+     *  * Activity is not letterboxed for fixed orientation
+     *
+     * Setting this property to `false` informs the system that the app must be
+     * opted-out from the compatibility treatment even if the device manufacturer has opted the app
+     * into the treatment.
+     *
+     * Not setting this property at all, or setting this property to `true` has no effect.
+     *
+     * **Syntax:**
+     * ```
+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED"
+     *     android:value="false" />
+     * </application>
+     * ```
+     */
+    // TODO(b/274924641): Make property public
+    const val PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED =
+        "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED"
+
+    /**
+     * Application level
+     * [PackageManager][android.content.pm.PackageManager.Property] tag
+     * for an app to inform the system that the app should be opted-out from the compatibility
+     * override that changes the min aspect ratio.
+     *
+     * When this compat override is enabled the min aspect ratio given in the app's manifest can
+     * be overridden by the device manufacturer using their discretion to improve display
+     * compatibility unless the app's manifest value is higher. This treatment will also apply if
+     * no min aspect ratio value is provided in the manifest. These treatments can apply only in
+     * specific cases (e.g. device is in portrait) or each time the app is displayed on screen.
+     *
+     * Setting this property to `false` informs the system that the app must be
+     * opted-out from the compatibility treatment even if the device manufacturer has opted the app
+     * into the treatment.
+     *
+     * Not setting this property at all, or setting this property to `true` has no effect.
+     *
+     * **Syntax:**
+     * ```
+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE"
+     *     android:value="false" />
+     * </application>
+     * ```
+     */
+    const val PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE =
+        "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE"
+
+    /**
+     * Application level
+     * [PackageManager][android.content.pm.PackageManager.Property] tag
+     * for an app to inform the system that the app should be opted-out from the
+     * compatibility overrides that change the resizability of the app.
+     *
+     * When these compat overrides are enabled they force the packages they are applied to to be
+     * resizable / unresizable. If the app is forced to be resizable this won't change whether
+     * the app can be put into multi-windowing mode, but allow the app to resize without going into
+     * size-compat mode when the window container resizes, such as display size change or screen
+     * rotation.
+     *
+     * Setting this property to `false` informs the system that the app must be
+     * opted-out from the compatibility treatment even if the device manufacturer has opted the app
+     * into the treatment.
+     *
+     * Not setting this property at all, or setting this property to `true` has no effect.
+     *
+     * **Syntax:**
+     * ```
+     * <application>
+     *   <property
+     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
+     *     android:value="false" />
+     * </application>
+     * ```
+     */
+    const val PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES =
+        "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"
 }
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt b/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt
index de0971a..5fc9638 100644
--- a/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt
+++ b/window/window/src/main/java/androidx/window/area/EmptyWindowAreaControllerImpl.kt
@@ -17,27 +17,36 @@
 package androidx.window.area
 
 import android.app.Activity
-import androidx.window.core.ExperimentalWindowApi
+import android.os.Binder
 import java.util.concurrent.Executor
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flowOf
 
 /**
- * Empty Implementation for devices that do not
- * support the [WindowAreaController] functionality
+ * Empty Implementation for devices that do not support the [WindowAreaController] functionality
  */
-@ExperimentalWindowApi
 internal class EmptyWindowAreaControllerImpl : WindowAreaController {
-    override fun rearDisplayStatus(): Flow<WindowAreaStatus> {
-        return flowOf(WindowAreaStatus.UNSUPPORTED)
-    }
 
-    override fun rearDisplayMode(
+    override val windowAreaInfos: Flow<List<WindowAreaInfo>>
+        get() = flowOf(listOf())
+
+    override fun transferActivityToWindowArea(
+        token: Binder,
         activity: Activity,
         executor: Executor,
         windowAreaSessionCallback: WindowAreaSessionCallback
     ) {
-        // TODO(b/269144982): Investigate not throwing an exception
-        throw UnsupportedOperationException("Rear Display mode cannot be enabled currently")
+        windowAreaSessionCallback.onSessionEnded(
+            IllegalStateException("There are no WindowAreas"))
+    }
+
+    override fun presentContentOnWindowArea(
+        token: Binder,
+        activity: Activity,
+        executor: Executor,
+        windowAreaPresentationSessionCallback: WindowAreaPresentationSessionCallback
+    ) {
+        windowAreaPresentationSessionCallback.onSessionEnded(
+            IllegalStateException("There are no WindowAreas"))
     }
 }
diff --git a/window/window/src/main/java/androidx/window/area/RearDisplayPresentationSessionPresenterImpl.kt b/window/window/src/main/java/androidx/window/area/RearDisplayPresentationSessionPresenterImpl.kt
new file mode 100644
index 0000000..4c06141
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/RearDisplayPresentationSessionPresenterImpl.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.window.area
+
+import android.content.Context
+import android.view.View
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation
+import androidx.window.extensions.area.WindowAreaComponent
+
+internal class RearDisplayPresentationSessionPresenterImpl(
+    private val windowAreaComponent: WindowAreaComponent,
+    private val presentation: ExtensionWindowAreaPresentation
+) : WindowAreaSessionPresenter {
+
+    override val context: Context = presentation.presentationContext
+
+    override fun setContentView(view: View) {
+        presentation.setPresentationView(view)
+    }
+
+    override fun close() {
+        windowAreaComponent.endRearDisplayPresentationSession()
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt b/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
index ae7d3ca..7a7299a 100644
--- a/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
+++ b/window/window/src/main/java/androidx/window/area/RearDisplaySessionImpl.kt
@@ -16,10 +16,8 @@
 
 package androidx.window.area
 
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.extensions.area.WindowAreaComponent
 
-@ExperimentalWindowApi
 internal class RearDisplaySessionImpl(
     private val windowAreaComponent: WindowAreaComponent
 ) : WindowAreaSession {
diff --git a/window/window/src/main/java/androidx/window/area/SafeWindowAreaComponentProvider.kt b/window/window/src/main/java/androidx/window/area/SafeWindowAreaComponentProvider.kt
new file mode 100644
index 0000000..8eb9696
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/SafeWindowAreaComponentProvider.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.window.area
+
+import androidx.window.SafeWindowExtensionsProvider
+import androidx.window.area.reflectionguard.WindowAreaComponentValidator.isExtensionWindowAreaPresentationValid
+import androidx.window.area.reflectionguard.WindowAreaComponentValidator.isExtensionWindowAreaStatusValid
+import androidx.window.area.reflectionguard.WindowAreaComponentValidator.isWindowAreaComponentValid
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.reflection.ReflectionUtils.doesReturn
+import androidx.window.reflection.ReflectionUtils.isPublic
+import androidx.window.reflection.ReflectionUtils.validateReflection
+import androidx.window.reflection.WindowExtensionsConstants
+
+/**
+ * Reflection Guard for [WindowAreaComponent].
+ * This will go through the [WindowAreaComponent]'s method by reflection and
+ * check each method's name and signature to see if the interface is what we required.
+ */
+internal class SafeWindowAreaComponentProvider(private val loader: ClassLoader) {
+
+    private val windowExtensions = SafeWindowExtensionsProvider(loader).windowExtensions
+
+    val windowAreaComponent: WindowAreaComponent?
+        get() {
+            return try {
+                if (
+                    windowExtensions != null &&
+                    isWindowAreaProviderValid(windowExtensions) &&
+                    isWindowAreaComponentValid(
+                        windowAreaComponentClass, ExtensionsUtil.safeVendorApiLevel
+                    ) &&
+                    isExtensionWindowAreaStatusValid(
+                        extensionWindowAreaStatusClass, ExtensionsUtil.safeVendorApiLevel
+                    ) &&
+                    isValidExtensionWindowPresentation()
+                ) windowExtensions.windowAreaComponent else null
+            } catch (e: Exception) {
+                null
+            }
+        }
+
+    private fun isWindowAreaProviderValid(windowExtensions: Any): Boolean {
+        return validateReflection(
+            "WindowExtensions#getWindowAreaComponent is not valid"
+        ) {
+            val getWindowAreaComponentMethod =
+                windowExtensions::class.java.getMethod("getWindowAreaComponent")
+            getWindowAreaComponentMethod.isPublic &&
+                getWindowAreaComponentMethod.doesReturn(windowAreaComponentClass)
+        }
+    }
+
+    private fun isValidExtensionWindowPresentation(): Boolean {
+        // Not required for API Level 2 or below
+        return ExtensionsUtil.safeVendorApiLevel <= 2 ||
+            isExtensionWindowAreaPresentationValid(
+                extensionWindowAreaPresentationClass, ExtensionsUtil.safeVendorApiLevel
+            )
+    }
+
+    private val windowAreaComponentClass: Class<*>
+        get() {
+            return loader.loadClass(WindowExtensionsConstants.WINDOW_AREA_COMPONENT_CLASS)
+        }
+
+    private val extensionWindowAreaStatusClass: Class<*>
+        get() {
+            return loader.loadClass(WindowExtensionsConstants.EXTENSION_WINDOW_AREA_STATUS_CLASS)
+        }
+
+    private val extensionWindowAreaPresentationClass: Class<*>
+        get() {
+            return loader.loadClass(
+                WindowExtensionsConstants.EXTENSION_WINDOW_AREA_PRESENTATION_CLASS
+            )
+        }
+}
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaAdapter.kt b/window/window/src/main/java/androidx/window/area/WindowAreaAdapter.kt
index 65154449..24e7152 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaAdapter.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaAdapter.kt
@@ -16,21 +16,31 @@
 
 package androidx.window.area
 
-import androidx.window.core.ExperimentalWindowApi
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_ACTIVE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_AVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNAVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNSUPPORTED
 import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_ACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_AVAILABLE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_UNAVAILABLE
+import androidx.window.extensions.area.WindowAreaComponent.STATUS_UNSUPPORTED
 
 /**
  * Adapter object to assist in translating values received from [WindowAreaComponent]
  * to developer friendly values in [WindowAreaController]
  */
-@ExperimentalWindowApi
 internal object WindowAreaAdapter {
 
-    internal fun translate(status: @WindowAreaComponent.WindowAreaStatus Int): WindowAreaStatus {
+    internal fun translate(
+        status: @WindowAreaComponent.WindowAreaStatus Int
+    ): WindowAreaCapability.Status {
         return when (status) {
-            WindowAreaComponent.STATUS_AVAILABLE -> WindowAreaStatus.AVAILABLE
-            WindowAreaComponent.STATUS_UNAVAILABLE -> WindowAreaStatus.UNAVAILABLE
-            else -> WindowAreaStatus.UNSUPPORTED
+            STATUS_UNSUPPORTED -> WINDOW_AREA_STATUS_UNSUPPORTED
+            STATUS_UNAVAILABLE -> WINDOW_AREA_STATUS_UNAVAILABLE
+            STATUS_AVAILABLE -> WINDOW_AREA_STATUS_AVAILABLE
+            STATUS_ACTIVE -> WINDOW_AREA_STATUS_ACTIVE
+            else -> WINDOW_AREA_STATUS_UNSUPPORTED
         }
     }
 }
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaCapability.kt b/window/window/src/main/java/androidx/window/area/WindowAreaCapability.kt
new file mode 100644
index 0000000..3346bf2
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaCapability.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.window.area
+
+import android.app.Activity
+
+/**
+ * Represents a capability for a [WindowAreaInfo].
+ */
+class WindowAreaCapability internal constructor(val operation: Operation, val status: Status) {
+    override fun toString(): String {
+        return "Operation: $operation: Status: $status"
+    }
+
+    /**
+     * Represents the status of availability for a specific [WindowAreaCapability]
+     */
+    class Status private constructor(private val description: String) {
+        override fun toString(): String {
+            return description
+        }
+
+        companion object {
+            /**
+             * Status indicating that the WindowArea feature is not a supported feature on the
+             * device.
+             */
+            @JvmField
+            val WINDOW_AREA_STATUS_UNSUPPORTED = Status("UNSUPPORTED")
+
+            /**
+             * Status indicating that the WindowArea feature is currently not available to be
+             * enabled. This could be because a different feature is active, or the current device
+             * configuration doesn't allow it.
+             */
+            @JvmField
+            val WINDOW_AREA_STATUS_UNAVAILABLE = Status("UNAVAILABLE")
+
+            /**
+             * Status indicating that the WindowArea feature is available to be enabled.
+             */
+            @JvmField
+            val WINDOW_AREA_STATUS_AVAILABLE = Status("AVAILABLE")
+
+            /**
+             * Status indicating that the WindowArea feature is currently active.
+             */
+            @JvmField
+            val WINDOW_AREA_STATUS_ACTIVE = Status("ACTIVE")
+        }
+    }
+
+    /**
+     * Represents an operation that a [WindowAreaInfo] may support.
+     */
+    class Operation private constructor(private val description: String) {
+        override fun toString(): String {
+            return description
+        }
+
+        companion object {
+
+            /**
+             * Operation that transfers an [Activity] into a [WindowAreaInfo]
+             */
+            @JvmField
+            val OPERATION_TRANSFER_ACTIVITY_TO_AREA = Operation("TRANSFER")
+
+            /**
+             * Operation that presents additional content into a [WindowAreaInfo]
+             */
+            @JvmField
+            val OPERATION_PRESENT_ON_AREA = Operation("PRESENT")
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        return other is WindowAreaCapability &&
+            operation == other.operation &&
+            status == other.status
+    }
+
+    override fun hashCode(): Int {
+        var result = operation.hashCode()
+        result = 31 * result + status.hashCode()
+        return result
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaController.kt b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
index cc6f9eb..0da0b8a 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaController.kt
@@ -17,55 +17,113 @@
 package androidx.window.area
 
 import android.app.Activity
+import android.os.Binder
 import android.os.Build
 import android.util.Log
 import androidx.annotation.RestrictTo
+import androidx.window.area.WindowAreaInfo.Type.Companion.TYPE_REAR_FACING
+import androidx.window.area.utils.DeviceUtils
 import androidx.window.core.BuildConfig
-import androidx.window.core.ExperimentalWindowApi
+import androidx.window.core.ExtensionsUtil
 import androidx.window.core.VerificationMode
-import androidx.window.extensions.WindowExtensionsProvider
-import androidx.window.extensions.area.WindowAreaComponent
 import java.util.concurrent.Executor
 import kotlinx.coroutines.flow.Flow
 
 /**
- * An interface to provide information about available window areas on the device and an option
- * to use the rear display area of a foldable device, exclusively or concurrently with the internal
- * display.
- *
- * @hide
+ * An interface to provide the information and behavior around moving windows between
+ * displays or display areas on a device.
  *
  */
-@ExperimentalWindowApi
 interface WindowAreaController {
 
     /**
-     * Provides information about the current state of the window area of the rear display on the
-     * device, if or when it is available. Rear Display mode can be invoked if the current status is
-     * [WindowAreaStatus.AVAILABLE].
+     * [Flow] of the list of current [WindowAreaInfo]s that are currently available to be interacted
+     * with.
      */
-    fun rearDisplayStatus(): Flow<WindowAreaStatus>
+    val windowAreaInfos: Flow<List<WindowAreaInfo>>
 
     /**
-     * Starts Rear Display Mode and moves the provided activity to the rear side of the device in
-     * order to face the same direction as the primary device camera(s). When a rear display
-     * mode is started, the system will turn on the rear display of the device to show the content
-     * there, and can disable the internal display. The provided [Activity] is likely to get a
-     * configuration change or being relaunched due to the difference in the internal and rear
-     * display sizes on the device.
-     * <p>Only the top visible application can request and use this mode. The system can dismiss the
-     * mode if the user changes the device state.
-     * <p>This method can only be called if the feature is supported on the device and is reported
-     * as available in the current state through [rearDisplayStatus], otherwise it will
-     * throw an [Exception].
+     * Starts a transfer session where the calling [Activity] is moved to the window area identified
+     * by the [token]. Updates on the session are provided through the [WindowAreaSessionCallback].
+     * Attempting to start a transfer session when the [WindowAreaInfo] does not return
+     * [WindowAreaCapability.Status.WINDOW_AREA_STATUS_AVAILABLE] will result in
+     * [WindowAreaSessionCallback.onSessionEnded] containing an [IllegalStateException]
+     *
+     * Only the top visible application can request to start a transfer session.
+     *
+     * The calling [Activity] will likely go through a configuration change since the window area
+     * it will be transferred to is usually different from the current area the [Activity] is in.
+     * The callback is retained during the lifetime of the session. If an [Activity] is captured in
+     * the callback and it does not handle the configuration change then it will be leaked. Consider
+     * using an [androidx.lifecycle.ViewModel] since that is meant to outlive the [Activity]
+     * lifecycle. If the [Activity] does override configuration changes, it is safe to have the
+     * [Activity] handle the WindowAreaSessionCallback. This guarantees that the calling [Activity]
+     * will continue to receive [WindowAreaSessionCallback.onSessionEnded] and keep a handle to the
+     * [WindowAreaSession] provided through [WindowAreaSessionCallback.onSessionStarted].
+     *
+     * The [windowAreaSessionCallback] provided will receive a call to
+     * [WindowAreaSessionCallback.onSessionStarted] after the [Activity] has been transferred to the
+     * window area. The transfer session will stay active until the session provided through
+     * [WindowAreaSessionCallback.onSessionStarted] is closed. Depending on the
+     * [WindowAreaInfo.Type] there may be other triggers that end the session, such as if a device
+     * state change makes the window area unavailable. One example of this is if the [Activity] is
+     * currently transferred to the [TYPE_REAR_FACING] window area of a foldable device, the session
+     * will be ended when the device is closed. When this occurs,
+     * [WindowAreaSessionCallback.onSessionEnded] is called.
+     *
+     * @param token [Binder] token identifying the window area to be transferred to.
+     * @param activity Base Activity making the call to [transferActivityToWindowArea].
+     * @param executor Executor used to provide updates to [windowAreaSessionCallback].
+     * @param windowAreaSessionCallback to be notified when the rear display session is started and
+     * ended.
+     *
+     * @see windowAreaInfos
      */
-    fun rearDisplayMode(
+    fun transferActivityToWindowArea(
+        token: Binder,
         activity: Activity,
         executor: Executor,
+        // TODO(272064992) investigate how to make this safer from leaks
         windowAreaSessionCallback: WindowAreaSessionCallback
     )
 
+    /**
+     * Starts a presentation session on the [WindowAreaInfo] identified by the [token] and sends
+     * updates through the [WindowAreaPresentationSessionCallback].
+     *
+     * If a presentation session is attempted to be started without it being available,
+     * [WindowAreaPresentationSessionCallback.onSessionEnded] will be called immediately with an
+     * [IllegalStateException].
+     *
+     * Only the top visible application can request to start a presentation session.
+     *
+     * The presentation session will stay active until the presentation provided through
+     * [WindowAreaPresentationSessionCallback.onSessionStarted] is closed. The [WindowAreaInfo.Type]
+     * may provide different triggers to close the session such as if the calling application
+     * is no longer in the foreground, or there is a device state change that makes the window area
+     * unavailable to be presented on. One example scenario is if a [TYPE_REAR_FACING] window area
+     * is being presented to on a foldable device that is open and has 2 screens. If the device is
+     * closed and the internal display is turned off, the session would be ended and
+     * [WindowAreaPresentationSessionCallback.onSessionEnded] is called to notify that the session
+     * has been ended. The session may end prematurely if the device gets to a critical thermal
+     * level, or if power saver mode is enabled.
+     *
+     * @param token [Binder] token to identify which [WindowAreaInfo] is to be presented on
+     * @param activity An [Activity] that will present content on the Rear Display.
+     * @param executor Executor used to provide updates to [windowAreaPresentationSessionCallback].
+     * @param windowAreaPresentationSessionCallback to be notified of updates to the lifecycle of
+     * the currently enabled rear display presentation.
+     * @see windowAreaInfos
+     */
+    fun presentContentOnWindowArea(
+        token: Binder,
+        activity: Activity,
+        executor: Executor,
+        windowAreaPresentationSessionCallback: WindowAreaPresentationSessionCallback
+    )
+
     public companion object {
+
         private val TAG = WindowAreaController::class.simpleName
 
         private var decorator: WindowAreaControllerDecorator = EmptyDecorator
@@ -76,24 +134,31 @@
         @JvmName("getOrCreate")
         @JvmStatic
         fun getOrCreate(): WindowAreaController {
-            var windowAreaComponentExtensions: WindowAreaComponent?
-            try {
-                // TODO(b/267972002): Introduce reflection guard for WindowAreaComponent
-                windowAreaComponentExtensions = WindowExtensionsProvider
-                    .getWindowExtensions()
-                    .windowAreaComponent
+            val windowAreaComponentExtensions = try {
+                this::class.java.classLoader?.let {
+                    SafeWindowAreaComponentProvider(it).windowAreaComponent
+                }
             } catch (t: Throwable) {
-                if (BuildConfig.verificationMode == VerificationMode.STRICT) {
+                if (BuildConfig.verificationMode == VerificationMode.LOG) {
                     Log.d(TAG, "Failed to load WindowExtensions")
                 }
-                windowAreaComponentExtensions = null
+                null
             }
+            val deviceSupported = Build.VERSION.SDK_INT > Build.VERSION_CODES.Q &&
+                windowAreaComponentExtensions != null &&
+                (ExtensionsUtil.safeVendorApiLevel >= 3 || DeviceUtils.hasDeviceMetrics(
+                    Build.MANUFACTURER,
+                    Build.MODEL
+                ))
+
             val controller =
-                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N ||
-                    windowAreaComponentExtensions == null) {
-                    EmptyWindowAreaControllerImpl()
+                if (deviceSupported) {
+                    WindowAreaControllerImpl(
+                        windowAreaComponentExtensions!!,
+                        ExtensionsUtil.safeVendorApiLevel
+                    )
                 } else {
-                    WindowAreaControllerImpl(windowAreaComponentExtensions)
+                    EmptyWindowAreaControllerImpl()
                 }
             return decorator.decorate(controller)
         }
@@ -116,7 +181,6 @@
  * Decorator that allows us to provide different functionality
  * in our window-testing artifact.
  */
-@ExperimentalWindowApi
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 interface WindowAreaControllerDecorator {
     /**
@@ -126,7 +190,6 @@
     public fun decorate(controller: WindowAreaController): WindowAreaController
 }
 
-@ExperimentalWindowApi
 private object EmptyDecorator : WindowAreaControllerDecorator {
     override fun decorate(controller: WindowAreaController): WindowAreaController {
         return controller
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt b/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt
index af9a398..57288d6 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaControllerImpl.kt
@@ -17,21 +17,29 @@
 package androidx.window.area
 
 import android.app.Activity
+import android.os.Binder
 import android.os.Build
 import android.util.Log
 import androidx.annotation.RequiresApi
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_ACTIVE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_AVAILABLE
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNSUPPORTED
+import androidx.window.area.utils.DeviceUtils
 import androidx.window.core.BuildConfig
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.core.VerificationMode
+import androidx.window.extensions.area.ExtensionWindowAreaStatus
 import androidx.window.extensions.area.WindowAreaComponent
 import androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_ACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_CONTENT_VISIBLE
 import androidx.window.extensions.area.WindowAreaComponent.SESSION_STATE_INACTIVE
+import androidx.window.extensions.area.WindowAreaComponent.WindowAreaSessionState
 import androidx.window.extensions.core.util.function.Consumer
+import androidx.window.layout.WindowMetrics
+import androidx.window.layout.WindowMetricsCalculator
 import java.util.concurrent.Executor
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
 
 /**
  * Implementation of WindowAreaController for devices
@@ -42,52 +50,243 @@
  * [Build.VERSION_CODES.S] as that's the min level of support for
  * this functionality.
  */
-@ExperimentalWindowApi
-@RequiresApi(Build.VERSION_CODES.N)
+@RequiresApi(Build.VERSION_CODES.Q)
 internal class WindowAreaControllerImpl(
-    private val windowAreaComponent: WindowAreaComponent
+    private val windowAreaComponent: WindowAreaComponent,
+    private val vendorApiLevel: Int
 ) : WindowAreaController {
 
-    private var currentStatus: WindowAreaStatus? = null
+    private lateinit var rearDisplaySessionConsumer: Consumer<Int>
+    private var currentRearDisplayModeStatus: WindowAreaCapability.Status =
+        WINDOW_AREA_STATUS_UNSUPPORTED
+    private var currentRearDisplayPresentationStatus: WindowAreaCapability.Status =
+        WINDOW_AREA_STATUS_UNSUPPORTED
 
-    override fun rearDisplayStatus(): Flow<WindowAreaStatus> {
-        return callbackFlow {
-            val listener = Consumer<@WindowAreaComponent.WindowAreaStatus Int> { status ->
-                currentStatus = WindowAreaAdapter.translate(status)
-                channel.trySend(currentStatus ?: WindowAreaStatus.UNSUPPORTED)
+    private val currentWindowAreaInfoMap = HashMap<String, WindowAreaInfo>()
+
+    override val windowAreaInfos: Flow<List<WindowAreaInfo>>
+        get() {
+            return callbackFlow {
+                val rearDisplayListener = Consumer<Int> { status ->
+                    updateRearDisplayAvailability(status)
+                    channel.trySend(currentWindowAreaInfoMap.values.toList())
+                }
+                val rearDisplayPresentationListener =
+                    Consumer<ExtensionWindowAreaStatus> { extensionWindowAreaStatus ->
+                        updateRearDisplayPresentationAvailability(extensionWindowAreaStatus)
+                        channel.trySend(currentWindowAreaInfoMap.values.toList())
+                    }
+
+                windowAreaComponent.addRearDisplayStatusListener(rearDisplayListener)
+                if (vendorApiLevel > 2) {
+                    windowAreaComponent.addRearDisplayPresentationStatusListener(
+                        rearDisplayPresentationListener
+                    )
+                }
+
+                awaitClose {
+                    windowAreaComponent.removeRearDisplayStatusListener(rearDisplayListener)
+                    if (vendorApiLevel > 2) {
+                        windowAreaComponent.removeRearDisplayPresentationStatusListener(
+                            rearDisplayPresentationListener
+                        )
+                    }
+                }
             }
-            windowAreaComponent.addRearDisplayStatusListener(listener)
-            awaitClose {
-                windowAreaComponent.removeRearDisplayStatusListener(listener)
+        }
+
+    private fun updateRearDisplayAvailability(
+        status: @WindowAreaComponent.WindowAreaStatus Int
+    ) {
+        val windowMetrics = if (vendorApiLevel >= 3) {
+            WindowMetricsCalculator.fromDisplayMetrics(
+                displayMetrics = windowAreaComponent.rearDisplayMetrics
+            )
+        } else {
+            val displayMetrics = DeviceUtils.getRearDisplayMetrics(Build.MANUFACTURER, Build.MODEL)
+            if (displayMetrics != null) {
+                WindowMetricsCalculator.fromDisplayMetrics(
+                    displayMetrics = displayMetrics
+                )
+            } else {
+                throw IllegalArgumentException(
+                    "DeviceUtils rear display metrics entry should not be null"
+                )
             }
-        }.distinctUntilChanged()
+        }
+
+        currentRearDisplayModeStatus = WindowAreaAdapter.translate(status)
+        updateRearDisplayWindowArea(
+            WindowAreaCapability.Operation.OPERATION_TRANSFER_ACTIVITY_TO_AREA,
+            currentRearDisplayModeStatus,
+            windowMetrics
+        )
     }
 
-    override fun rearDisplayMode(
+    private fun updateRearDisplayPresentationAvailability(
+        extensionWindowAreaStatus: ExtensionWindowAreaStatus
+    ) {
+        currentRearDisplayPresentationStatus =
+            WindowAreaAdapter.translate(extensionWindowAreaStatus.windowAreaStatus)
+        val windowMetrics = WindowMetricsCalculator.fromDisplayMetrics(
+            displayMetrics = extensionWindowAreaStatus.windowAreaDisplayMetrics
+        )
+
+        updateRearDisplayWindowArea(
+            WindowAreaCapability.Operation.OPERATION_PRESENT_ON_AREA,
+            currentRearDisplayPresentationStatus,
+            windowMetrics,
+        )
+    }
+
+    /**
+     * Updates the [WindowAreaInfo] object with the [REAR_DISPLAY_BINDER_DESCRIPTOR] binder token
+     * with the updated [status] corresponding to the [operation] and with the updated [metrics]
+     * received from the device for this window area.
+     *
+     * @param operation Operation that we are updating the status of.
+     * @param status New status for the operation provided on this window area.
+     * @param metrics Updated [WindowMetrics] for this window area.
+     */
+    private fun updateRearDisplayWindowArea(
+        operation: WindowAreaCapability.Operation,
+        status: WindowAreaCapability.Status,
+        metrics: WindowMetrics,
+    ) {
+        var rearDisplayAreaInfo: WindowAreaInfo? =
+            currentWindowAreaInfoMap[REAR_DISPLAY_BINDER_DESCRIPTOR]
+        if (status == WINDOW_AREA_STATUS_UNSUPPORTED) {
+            rearDisplayAreaInfo?.let { info ->
+                if (shouldRemoveWindowAreaInfo(info)) {
+                    currentWindowAreaInfoMap.remove(REAR_DISPLAY_BINDER_DESCRIPTOR)
+                } else {
+                    val capability = WindowAreaCapability(operation, status)
+                    info.capabilityMap[operation] = capability
+                }
+            }
+        } else {
+            if (rearDisplayAreaInfo == null) {
+                rearDisplayAreaInfo = WindowAreaInfo(
+                    metrics = metrics,
+                    type = WindowAreaInfo.Type.TYPE_REAR_FACING,
+                    // TODO(b/273807238): Update extensions to send the binder token and type
+                    token = Binder(REAR_DISPLAY_BINDER_DESCRIPTOR),
+                    windowAreaComponent = windowAreaComponent
+                )
+            }
+            val capability = WindowAreaCapability(operation, status)
+            rearDisplayAreaInfo.capabilityMap[operation] = capability
+            rearDisplayAreaInfo.metrics = metrics
+            currentWindowAreaInfoMap[REAR_DISPLAY_BINDER_DESCRIPTOR] = rearDisplayAreaInfo
+        }
+    }
+
+    /**
+     * Determines if a [WindowAreaInfo] should be removed from [windowAreaInfos] if all
+     * [WindowAreaCapability] are currently [WINDOW_AREA_STATUS_UNSUPPORTED]
+     */
+    private fun shouldRemoveWindowAreaInfo(windowAreaInfo: WindowAreaInfo): Boolean {
+        for (capability: WindowAreaCapability in windowAreaInfo.capabilityMap.values) {
+            if (capability.status != WINDOW_AREA_STATUS_UNSUPPORTED) {
+                return false
+            }
+        }
+        return true
+    }
+
+    override fun transferActivityToWindowArea(
+        token: Binder,
+        activity: Activity,
+        executor: Executor,
+        windowAreaSessionCallback: WindowAreaSessionCallback
+        ) {
+        if (token.interfaceDescriptor == REAR_DISPLAY_BINDER_DESCRIPTOR) {
+            startRearDisplayMode(activity, executor, windowAreaSessionCallback)
+        }
+    }
+
+    override fun presentContentOnWindowArea(
+        token: Binder,
+        activity: Activity,
+        executor: Executor,
+        windowAreaPresentationSessionCallback: WindowAreaPresentationSessionCallback
+    ) {
+        if (token.interfaceDescriptor == REAR_DISPLAY_BINDER_DESCRIPTOR) {
+            startRearDisplayPresentationMode(
+                activity,
+                executor,
+                windowAreaPresentationSessionCallback
+            )
+        }
+    }
+
+    private fun startRearDisplayMode(
         activity: Activity,
         executor: Executor,
         windowAreaSessionCallback: WindowAreaSessionCallback
     ) {
-        // If we already have a status value that is not [WindowAreaStatus.AVAILABLE]
-        // we should throw an exception quick to indicate they tried to enable
-        // RearDisplay mode when it was not available.
-        if (currentStatus != null && currentStatus != WindowAreaStatus.AVAILABLE) {
-            throw UnsupportedOperationException("Rear Display mode cannot be enabled currently")
+        // If the capability is currently active, provide an error pointing the developer on how to
+        // get access to the current session
+        if (currentRearDisplayModeStatus == WINDOW_AREA_STATUS_ACTIVE) {
+            windowAreaSessionCallback.onSessionEnded(
+                IllegalStateException(
+                    "The WindowArea feature is currently active, WindowAreaInfo#getActiveSession" +
+                        "can be used to get an instance of the current active session"
+                )
+            )
+            return
         }
-        val rearDisplaySessionConsumer =
+
+        // If we already have an availability value that is not
+        // [Availability.WINDOW_AREA_CAPABILITY_AVAILABLE] we should end the session and pass an
+        // exception to indicate they tried to enable rear display mode when it was not available.
+        if (currentRearDisplayModeStatus != WINDOW_AREA_STATUS_AVAILABLE) {
+            windowAreaSessionCallback.onSessionEnded(
+                IllegalStateException(
+                    "The WindowArea feature is currently not available to be entered"
+                )
+            )
+            return
+        }
+
+        rearDisplaySessionConsumer =
             RearDisplaySessionConsumer(executor, windowAreaSessionCallback, windowAreaComponent)
         windowAreaComponent.startRearDisplaySession(activity, rearDisplaySessionConsumer)
     }
 
+    private fun startRearDisplayPresentationMode(
+        activity: Activity,
+        executor: Executor,
+        windowAreaPresentationSessionCallback: WindowAreaPresentationSessionCallback
+    ) {
+        if (currentRearDisplayPresentationStatus != WINDOW_AREA_STATUS_AVAILABLE) {
+            windowAreaPresentationSessionCallback.onSessionEnded(
+                IllegalStateException(
+                    "The WindowArea feature is currently not available to be entered"
+                )
+            )
+            return
+        }
+
+        windowAreaComponent.startRearDisplayPresentationSession(
+            activity,
+            RearDisplayPresentationSessionConsumer(
+                executor,
+                windowAreaPresentationSessionCallback,
+                windowAreaComponent
+            )
+        )
+    }
+
     internal class RearDisplaySessionConsumer(
         private val executor: Executor,
         private val appCallback: WindowAreaSessionCallback,
         private val extensionsComponent: WindowAreaComponent
-    ) : Consumer<@WindowAreaComponent.WindowAreaSessionState Int> {
+    ) : Consumer<Int> {
 
         private var session: WindowAreaSession? = null
 
-        override fun accept(t: @WindowAreaComponent.WindowAreaSessionState Int) {
+        override fun accept(t: Int) {
             when (t) {
                 SESSION_STATE_ACTIVE -> onSessionStarted()
                 SESSION_STATE_INACTIVE -> onSessionFinished()
@@ -107,11 +306,58 @@
 
         private fun onSessionFinished() {
             session = null
-            executor.execute { appCallback.onSessionEnded() }
+            executor.execute { appCallback.onSessionEnded(null) }
+        }
+    }
+
+    internal class RearDisplayPresentationSessionConsumer(
+        private val executor: Executor,
+        private val windowAreaPresentationSessionCallback: WindowAreaPresentationSessionCallback,
+        private val windowAreaComponent: WindowAreaComponent
+    ) : Consumer<@WindowAreaSessionState Int> {
+
+        private var lastReportedSessionStatus: @WindowAreaSessionState Int = SESSION_STATE_INACTIVE
+        override fun accept(t: @WindowAreaSessionState Int) {
+            val previousStatus: @WindowAreaSessionState Int = lastReportedSessionStatus
+            lastReportedSessionStatus = t
+
+            executor.execute {
+                when (t) {
+                    SESSION_STATE_ACTIVE -> {
+                        // If the last status was visible, then ACTIVE infers the content is no
+                        // longer visible.
+                        if (previousStatus == SESSION_STATE_CONTENT_VISIBLE) {
+                            windowAreaPresentationSessionCallback.onContainerVisibilityChanged(
+                                false /* isVisible */
+                            )
+                        } else {
+                            // Presentation should never be null if the session is active
+                            windowAreaPresentationSessionCallback.onSessionStarted(
+                                RearDisplayPresentationSessionPresenterImpl(
+                                    windowAreaComponent,
+                                    windowAreaComponent.rearDisplayPresentation!!
+                                )
+                            )
+                        }
+                    }
+
+                    SESSION_STATE_CONTENT_VISIBLE ->
+                        windowAreaPresentationSessionCallback.onContainerVisibilityChanged(true)
+
+                    SESSION_STATE_INACTIVE ->
+                        windowAreaPresentationSessionCallback.onSessionEnded(null)
+
+                    else -> {
+                        Log.e(TAG, "Invalid session state value received: $t")
+                    }
+                }
+            }
         }
     }
 
     internal companion object {
         private val TAG = WindowAreaControllerImpl::class.simpleName
+
+        private const val REAR_DISPLAY_BINDER_DESCRIPTOR = "WINDOW_AREA_REAR_DISPLAY"
     }
 }
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaInfo.kt b/window/window/src/main/java/androidx/window/area/WindowAreaInfo.kt
new file mode 100644
index 0000000..e38bdaa
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaInfo.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.window.area
+
+import android.os.Binder
+import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_PRESENT_ON_AREA
+import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_TRANSFER_ACTIVITY_TO_AREA
+import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_ACTIVE
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.layout.WindowMetrics
+
+/**
+ * The current state of a window area. The [WindowAreaInfo] can represent a part of or an entire
+ * display in the system. These values can be used to modify the UI to show/hide controls and
+ * determine when features can be enabled.
+ */
+class WindowAreaInfo internal constructor(
+
+    /**
+     * The [WindowMetrics] that represent the size of the area. Used to determine if the behavior
+     * desired fits the size of the window area available.
+     */
+    var metrics: WindowMetrics,
+
+    /**
+     * The [Type] of this window area
+     */
+    val type: Type,
+
+    /**
+     * [Binder] token to identify the specific WindowArea
+     */
+    val token: Binder,
+
+    private val windowAreaComponent: WindowAreaComponent
+) {
+
+    internal val capabilityMap = HashMap<WindowAreaCapability.Operation, WindowAreaCapability>()
+
+    /**
+     * Returns the [WindowAreaCapability] corresponding to the [operation] provided. If this
+     * [WindowAreaCapability] does not exist for this [WindowAreaInfo], null is returned.
+     */
+    fun getCapability(operation: WindowAreaCapability.Operation): WindowAreaCapability? {
+        return capabilityMap[operation]
+    }
+
+    /**
+     * Returns the current active [WindowAreaSession] is one is currently active for the provided
+     * [operation]
+     *
+     * @throws IllegalStateException if there is no active session for the provided [operation]
+     */
+    fun getActiveSession(operation: WindowAreaCapability.Operation): WindowAreaSession? {
+        if (getCapability(operation)?.status != WINDOW_AREA_STATUS_ACTIVE) {
+            throw IllegalStateException("No session is currently active")
+        }
+
+        if (type == Type.TYPE_REAR_FACING) {
+            // TODO(b/273807246) We should cache instead of always creating a new session
+            return createRearFacingSession(operation)
+        }
+        return null
+    }
+
+    private fun createRearFacingSession(
+        operation: WindowAreaCapability.Operation
+    ): WindowAreaSession {
+        return when (operation) {
+            OPERATION_TRANSFER_ACTIVITY_TO_AREA -> RearDisplaySessionImpl(windowAreaComponent)
+            OPERATION_PRESENT_ON_AREA ->
+                RearDisplayPresentationSessionPresenterImpl(
+                    windowAreaComponent,
+                    windowAreaComponent.rearDisplayPresentation!!
+                )
+            else -> {
+                throw IllegalArgumentException("Invalid operation provided")
+            }
+        }
+    }
+
+    /**
+     * Represents a type of [WindowAreaInfo]
+     */
+    class Type private constructor(private val description: String) {
+        override fun toString(): String {
+            return description
+        }
+
+        companion object {
+            /**
+             * Type of window area that is facing the same direction as the rear camera(s) on the
+             * device.
+             */
+            @JvmField
+            val TYPE_REAR_FACING = Type("REAR FACING")
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        return other is WindowAreaInfo &&
+            metrics == other.metrics &&
+            type == other.type &&
+            capabilityMap.entries == other.capabilityMap.entries
+    }
+
+    override fun hashCode(): Int {
+        var result = metrics.hashCode()
+        result = 31 * result + type.hashCode()
+        result = 31 * result + capabilityMap.entries.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "WindowAreaInfo{ Metrics: $metrics, type: $type, " +
+            "Capabilities: ${capabilityMap.entries} }"
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaPresentationSessionCallback.kt b/window/window/src/main/java/androidx/window/area/WindowAreaPresentationSessionCallback.kt
new file mode 100644
index 0000000..2d4b8ce
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaPresentationSessionCallback.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.window.area
+
+import android.content.Context
+import android.view.View
+
+/**
+ * A callback to notify about the lifecycle of a window area presentation session.
+ *
+ * @see WindowAreaController.presentContentOnWindowArea
+ */
+interface WindowAreaPresentationSessionCallback {
+
+    /**
+     * Notifies about a start of a presentation session. Provides a reference to
+     * [WindowAreaSessionPresenter] to allow an application to customize a presentation when the
+     * session starts. The [Context] provided from the [WindowAreaSessionPresenter] should be used
+     * to inflate or make any UI decisions around the presentation [View] that should be shown in
+     * that area.
+     */
+    fun onSessionStarted(session: WindowAreaSessionPresenter)
+
+    /**
+     * Notifies about an end of a presentation session. The presentation and any app-provided
+     * content in the window area is removed.
+     *
+     * @param t [Throwable] to provide information on if the session was ended due to an error.
+     * This will only occur if a session is attempted to be enabled when it is not available, but
+     * can be expanded to alert for more errors in the future.
+     */
+    fun onSessionEnded(t: Throwable?)
+
+    /**
+     * Notifies about changes in visibility of a container that can hold the app content to show
+     * in the window area. Notification of the container being visible is guaranteed to occur after
+     * [onSessionStarted] has been called. The container being no longer visible is guaranteed to
+     * occur before [onSessionEnded].
+     *
+     * If content was never presented, then this method will never be called.
+     */
+    fun onContainerVisibilityChanged(isVisible: Boolean)
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt b/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
index e3e4bff..92872c8 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaSession.kt
@@ -16,17 +16,15 @@
 
 package androidx.window.area
 
-import androidx.window.core.ExperimentalWindowApi
-
 /**
- * Session interface to represent a long-standing
- * WindowArea mode or feature that provides a handle
- * to close the session.
+ * Session interface to represent an active window area feature.
  *
- * @hide
- *
+ * @see WindowAreaSessionCallback.onSessionStarted
  */
-@ExperimentalWindowApi
 interface WindowAreaSession {
+
+    /**
+     * Closes the active session, no-op if the session is not currently active.
+     */
     fun close()
 }
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt b/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
index 7527d53..309ba5c 100644
--- a/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaSessionCallback.kt
@@ -16,20 +16,25 @@
 
 package androidx.window.area
 
-import androidx.window.core.ExperimentalWindowApi
-
 /**
- * Callback to update the client on the WindowArea Session being
+ *  Callback to update the client on the WindowArea Session being
  * started and ended.
  * TODO(b/207720511) Move to window-java module when Kotlin API Finalized
- *
- * @hide
- *
  */
-@ExperimentalWindowApi
 interface WindowAreaSessionCallback {
 
+    /**
+     * Notifies about a start of a session. Provides a reference to the current [WindowAreaSession]
+     * the application the ability to close the session through [WindowAreaSession.close].
+     */
     fun onSessionStarted(session: WindowAreaSession)
 
-    fun onSessionEnded()
+    /**
+     * Notifies about an end of a [WindowAreaSession].
+     *
+     * @param t [Throwable] to provide information on if the session was ended due to an error.
+     * This will only occur if a session is attempted to be enabled when it is not available, but
+     * can be expanded to alert for more errors in the future.
+     */
+    fun onSessionEnded(t: Throwable?)
 }
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaSessionPresenter.kt b/window/window/src/main/java/androidx/window/area/WindowAreaSessionPresenter.kt
new file mode 100644
index 0000000..bc8bfc8
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/WindowAreaSessionPresenter.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.window.area
+
+import android.content.Context
+import android.view.View
+
+/**
+ * A container that allows getting access to and showing content on a window area. The container is
+ * provided from [WindowAreaPresentationSessionCallback] when a requested session becomes active.
+ * The presentation can be automatically dismissed by the system when the user leaves the primary
+ * application window, or can be closed by calling [WindowAreaSessionPresenter.close].
+ * @see WindowAreaController.presentContentOnWindowArea
+ */
+interface WindowAreaSessionPresenter : WindowAreaSession {
+    /**
+     * Returns the [Context] associated with the window area.
+     */
+    val context: Context
+
+    /**
+     * Sets a [View] to show on a window area. After setting the view the system can turn on the
+     * corresponding display and start showing content.
+     */
+    fun setContentView(view: View)
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt b/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt
deleted file mode 100644
index 732da7d..0000000
--- a/window/window/src/main/java/androidx/window/area/WindowAreaStatus.kt
+++ /dev/null
@@ -1,56 +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.window.area
-
-import androidx.window.core.ExperimentalWindowApi
-
-/**
- * Represents a window area status.
- *
- * @hide
- *
- */
-@ExperimentalWindowApi
-class WindowAreaStatus private constructor(private val mDescription: String) {
-
-    override fun toString(): String {
-        return mDescription
-    }
-
-    companion object {
-        /**
-         * Status representing that the WindowArea feature is not a supported
-         * feature on the device.
-         */
-        @JvmField
-        val UNSUPPORTED = WindowAreaStatus("UNSUPPORTED")
-
-        /**
-         * Status representing that the WindowArea feature is currently not available
-         * to be enabled. This could be due to another process has enabled it, or that the
-         * current device configuration doesn't allow it.
-         */
-        @JvmField
-        val UNAVAILABLE = WindowAreaStatus("UNAVAILABLE")
-
-        /**
-         * Status representing that the WindowArea feature is available to be enabled.
-         */
-        @JvmField
-        val AVAILABLE = WindowAreaStatus("AVAILABLE")
-    }
-}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaPresentationRequirements.java b/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaPresentationRequirements.java
new file mode 100644
index 0000000..9153250
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaPresentationRequirements.java
@@ -0,0 +1,37 @@
+/*
+ * 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.window.area.reflectionguard;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation;
+
+/**
+ * API requirements for [ExtensionWindowAreaPresentation]
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public interface ExtensionWindowAreaPresentationRequirements {
+    /** @see ExtensionWindowAreaPresentation#getPresentationContext */
+    @NonNull
+    Context getPresentationContext();
+
+    /** @see ExtensionWindowAreaPresentation#setPresentationView */
+    void setPresentationView(@NonNull View view);
+}
diff --git a/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaStatusRequirements.java b/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaStatusRequirements.java
new file mode 100644
index 0000000..14ba999
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/reflectionguard/ExtensionWindowAreaStatusRequirements.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.area.reflectionguard;
+
+import android.util.DisplayMetrics;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.area.ExtensionWindowAreaStatus;
+
+/**
+ * API requirements for [ExtensionWindowAreaStatus]
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public interface ExtensionWindowAreaStatusRequirements {
+    /** @see ExtensionWindowAreaStatus#getWindowAreaStatus */
+    int getWindowAreaStatus();
+
+    /** @see ExtensionWindowAreaStatus#getWindowAreaDisplayMetrics */
+    @NonNull
+    DisplayMetrics getWindowAreaDisplayMetrics();
+}
diff --git a/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi2Requirements.java b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi2Requirements.java
new file mode 100644
index 0000000..0ab78c0
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi2Requirements.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.area.reflectionguard;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.core.util.function.Consumer;
+
+/**
+ * This file defines the Vendor API Level 2 Requirements for WindowAreaComponent. This is used
+ * in the client library to perform reflection guard to ensure that the OEM extension implementation
+ * is complete.
+ *
+ * @see WindowAreaComponent
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public interface WindowAreaComponentApi2Requirements {
+
+    /** @see WindowAreaComponent#addRearDisplayStatusListener */
+    void addRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
+
+    /** @see WindowAreaComponent#removeRearDisplayStatusListener */
+    void removeRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
+
+    /** @see WindowAreaComponent#startRearDisplaySession */
+    void startRearDisplaySession(@NonNull Activity activity,
+            @NonNull Consumer<Integer> consumer);
+
+    /** @see WindowAreaComponent#endRearDisplaySession */
+    void endRearDisplaySession();
+}
diff --git a/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi3Requirements.java b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi3Requirements.java
new file mode 100644
index 0000000..56c54aa
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentApi3Requirements.java
@@ -0,0 +1,63 @@
+/*
+ * 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.window.area.reflectionguard;
+
+import android.app.Activity;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation;
+import androidx.window.extensions.area.ExtensionWindowAreaStatus;
+import androidx.window.extensions.area.WindowAreaComponent;
+import androidx.window.extensions.core.util.function.Consumer;
+
+
+/**
+ * This file defines the Vendor API Level 3 Requirements for WindowAreaComponent. This is used
+ * in the client library to perform reflection guard to ensure that the OEM extension implementation
+ * is complete.
+ *
+ * @see WindowAreaComponent
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public interface WindowAreaComponentApi3Requirements extends WindowAreaComponentApi2Requirements {
+
+    /** @see WindowAreaComponent#addRearDisplayPresentationStatusListener */
+    void addRearDisplayPresentationStatusListener(
+            @NonNull Consumer<ExtensionWindowAreaStatus> consumer);
+
+    /** @see WindowAreaComponent#removeRearDisplayPresentationStatusListener */
+    void removeRearDisplayPresentationStatusListener(
+            @NonNull Consumer<ExtensionWindowAreaStatus> consumer);
+
+    /** @see WindowAreaComponent#startRearDisplayPresentationSession */
+    void startRearDisplayPresentationSession(@NonNull Activity activity,
+            @NonNull Consumer<Integer> consumer);
+
+    /** @see WindowAreaComponent#endRearDisplayPresentationSession */
+    void endRearDisplayPresentationSession();
+
+    /** @see WindowAreaComponent#getRearDisplayPresentation */
+    @Nullable
+    ExtensionWindowAreaPresentation getRearDisplayPresentation();
+
+    /** @see WindowAreaComponent#getRearDisplayMetrics() */
+    @NonNull
+    DisplayMetrics getRearDisplayMetrics();
+}
diff --git a/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentValidator.kt b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentValidator.kt
new file mode 100644
index 0000000..d48d2ab
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/reflectionguard/WindowAreaComponentValidator.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.window.area.reflectionguard
+
+import androidx.window.extensions.area.ExtensionWindowAreaPresentation
+import androidx.window.extensions.area.WindowAreaComponent
+import androidx.window.reflection.ReflectionUtils.validateImplementation
+
+/**
+ * Utility class to validate [WindowAreaComponent] implementation.
+ */
+internal object WindowAreaComponentValidator {
+
+    internal fun isWindowAreaComponentValid(windowAreaComponent: Class<*>, apiLevel: Int): Boolean {
+        return when {
+            apiLevel <= 1 -> false
+            apiLevel == 2 -> validateImplementation(
+                windowAreaComponent, WindowAreaComponentApi2Requirements::class.java
+            )
+            else -> validateImplementation(
+                windowAreaComponent, WindowAreaComponentApi3Requirements::class.java
+            )
+        }
+    }
+
+    internal fun isExtensionWindowAreaStatusValid(
+        extensionWindowAreaStatus: Class<*>,
+        apiLevel: Int
+    ): Boolean {
+        return when {
+            apiLevel <= 1 -> false
+            else -> validateImplementation(
+                extensionWindowAreaStatus, ExtensionWindowAreaStatusRequirements::class.java
+            )
+        }
+    }
+
+    internal fun isExtensionWindowAreaPresentationValid(
+        extensionWindowAreaPresentation: Class<*>,
+        apiLevel: Int
+    ): Boolean {
+        return when {
+            apiLevel <= 2 -> false
+            else -> validateImplementation(
+                extensionWindowAreaPresentation, ExtensionWindowAreaPresentation::class.java
+            )
+        }
+    }
+}
diff --git a/window/window/src/main/java/androidx/window/area/utils/DeviceMetrics.kt b/window/window/src/main/java/androidx/window/area/utils/DeviceMetrics.kt
new file mode 100644
index 0000000..009d892
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/utils/DeviceMetrics.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.area.utils
+
+import android.os.Build
+import android.util.DisplayMetrics
+import androidx.annotation.RequiresApi
+
+/**
+ * Data class holding metrics about a specific device.
+ */
+@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+internal class DeviceMetrics(
+    val manufacturer: String,
+    val model: String,
+    val rearDisplayMetrics: DisplayMetrics
+) {
+    override fun equals(other: Any?): Boolean {
+        return other is DeviceMetrics &&
+            manufacturer == other.manufacturer &&
+            model == other.model &&
+            rearDisplayMetrics.equals(other.rearDisplayMetrics)
+    }
+
+    override fun hashCode(): Int {
+        var result = manufacturer.hashCode()
+        result = 31 * result + model.hashCode()
+        result = 31 * result + rearDisplayMetrics.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "DeviceMetrics{ Manufacturer: $manufacturer, model: $model, " +
+            "Rear display metrics: $rearDisplayMetrics }"
+    }
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/area/utils/DeviceUtils.kt b/window/window/src/main/java/androidx/window/area/utils/DeviceUtils.kt
new file mode 100644
index 0000000..44bb3fa
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/area/utils/DeviceUtils.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.window.area.utils
+
+import android.os.Build
+import android.util.DisplayMetrics
+import androidx.annotation.RequiresApi
+import java.util.Locale
+
+/**
+ * Utility object to provide information about specific devices that may not be available
+ * through the extensions API at a certain vendor API level
+ */
+@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+internal object DeviceUtils {
+
+    private val deviceList = listOf(DeviceMetrics("google", "pixel fold",
+        DisplayMetrics().apply {
+            widthPixels = 1080
+            heightPixels = 2092
+            density = 2.625f
+            densityDpi = 420 }
+        ))
+
+    internal fun hasDeviceMetrics(manufacturer: String, model: String): Boolean {
+        return deviceList.any {
+            it.manufacturer == manufacturer.lowercase(Locale.US) &&
+                it.model == model.lowercase(Locale.US)
+        }
+    }
+
+    internal fun getRearDisplayMetrics(manufacturer: String, model: String): DisplayMetrics? {
+        return deviceList.firstOrNull {
+            it.manufacturer == manufacturer.lowercase(Locale.US) &&
+                it.model == model.lowercase(Locale.US)
+        }?.rearDisplayMetrics
+    }
+}
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
index 219cb1f..8adffae 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingController.kt
@@ -17,7 +17,10 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.app.ActivityOptions
 import android.content.Context
+import android.os.IBinder
+import androidx.window.core.ExperimentalWindowApi
 
 /** The controller that allows checking the current [Activity] embedding status. */
 class ActivityEmbeddingController internal constructor(private val backend: EmbeddingBackend) {
@@ -31,6 +34,68 @@
     fun isActivityEmbedded(activity: Activity): Boolean =
         backend.isActivityEmbedded(activity)
 
+    /**
+     * Returns the [ActivityStack] that this [activity] is part of when it is being organized in the
+     * embedding container and associated with a [SplitInfo]. Returns `null` if there is no such
+     * [ActivityStack].
+     *
+     * @param activity The [Activity] to check.
+     * @return the [ActivityStack] that this [activity] is part of, or `null` if there is no such
+     *   [ActivityStack].
+     */
+    @ExperimentalWindowApi
+    fun getActivityStack(activity: Activity): ActivityStack? =
+        backend.getActivityStack(activity)
+
+    /**
+     * Sets the launching [ActivityStack] to the given [android.app.ActivityOptions].
+     *
+     * @param options The [android.app.ActivityOptions] to be updated.
+     * @param token The token of the [ActivityStack] to be set.
+     */
+    internal fun setLaunchingActivityStack(
+        options: ActivityOptions,
+        token: IBinder
+    ): ActivityOptions {
+        return backend.setLaunchingActivityStack(options, token)
+    }
+
+    /**
+     * Finishes a set of [activityStacks][ActivityStack] from the lowest to the highest z-order
+     * regardless of the order of [ActivityStack] set.
+     *
+     * If the remaining [ActivityStack] from a split participates in other splits with other
+     * `activityStacks`, they might be showing instead. For example, if activityStack A splits with
+     * activityStack B and C, and activityStack C covers activityStack B, finishing activityStack C
+     * might make the split of activityStack A and B show.
+     *
+     * If all associated `activityStacks` of a [ActivityStack] are finished, the [ActivityStack]
+     * will be expanded to fill the parent task container. This is useful to expand the primary
+     * container as the sample linked below shows.
+     *
+     * **Note** that it's caller's responsibility to check whether this API is supported by calling
+     * [isFinishingActivityStacksSupported]. If not, an alternative approach to finishing all
+     * containers above a particular activity can be to launch it again with flag
+     * [android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP].
+     *
+     * @param activityStacks The set of [ActivityStack] to be finished.
+     * @throws UnsupportedOperationException if this device doesn't support this API and
+     * [isFinishingActivityStacksSupported] returns `false`.
+     * @sample androidx.window.samples.embedding.expandPrimaryContainer
+     */
+    @ExperimentalWindowApi
+    fun finishActivityStacks(activityStacks: Set<ActivityStack>) =
+        backend.finishActivityStacks(activityStacks)
+
+    /**
+     * Checks whether [finishActivityStacks] is supported.
+     *
+     * @return `true` if [finishActivityStacks] is supported on the device, `false` otherwise.
+     */
+    @ExperimentalWindowApi
+    fun isFinishingActivityStacksSupported(): Boolean =
+        backend.isFinishActivityStacksSupported()
+
     companion object {
         /**
          * Obtains an instance of [ActivityEmbeddingController].
@@ -43,4 +108,4 @@
             return ActivityEmbeddingController(backend)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt
new file mode 100644
index 0000000..190ffa3
--- /dev/null
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityEmbeddingOptions.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("ActivityEmbeddingOptions")
+
+package androidx.window.embedding
+
+import android.app.Activity
+import android.app.ActivityOptions
+import android.content.Context
+import androidx.window.core.ExperimentalWindowApi
+import androidx.window.core.ExtensionsUtil
+import androidx.window.extensions.WindowExtensions
+
+/**
+ * Sets the launching [ActivityStack] to the given [android.app.ActivityOptions].
+ *
+ * If the device doesn't support setting launching, [UnsupportedOperationException] will be thrown.
+ * @see isSetLaunchingActivityStackSupported
+ *
+ * @param context The [android.content.Context] that is going to be used for launching
+ * activity with this [android.app.ActivityOptions], which is usually be the [android.app.Activity]
+ * of the app that hosts the task.
+ * @param activityStack The target [ActivityStack] for launching.
+ * @throws UnsupportedOperationException if this device doesn't support this API.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.setLaunchingActivityStack(
+    context: Context,
+    activityStack: ActivityStack
+): ActivityOptions = let {
+    if (!isSetLaunchingActivityStackSupported()) {
+        throw UnsupportedOperationException("#setLaunchingActivityStack is not " +
+            "supported on the device.")
+    } else {
+        ActivityEmbeddingController.getInstance(context)
+            .setLaunchingActivityStack(this, activityStack.token)
+    }
+}
+
+/**
+ * Sets the launching [ActivityStack] to the [android.app.ActivityOptions] by the
+ * given [activity]. That is, the [ActivityStack] of the given [activity] is the
+ * [ActivityStack] used for launching.
+ *
+ * If the device doesn't support setting launching or no available [ActivityStack]
+ * can be found from the given [activity], [UnsupportedOperationException] will be thrown.
+ * @see isSetLaunchingActivityStackSupported
+ *
+ * @param activity The existing [android.app.Activity] on the target [ActivityStack].
+ * @throws UnsupportedOperationException if this device doesn't support this API or no
+ * available [ActivityStack] can be found.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.setLaunchingActivityStack(activity: Activity): ActivityOptions {
+    val activityStack =
+        ActivityEmbeddingController.getInstance(activity).getActivityStack(activity)
+    return if (activityStack != null) {
+        setLaunchingActivityStack(activity, activityStack)
+    } else {
+        throw UnsupportedOperationException("No available ActivityStack found. " +
+            "The given activity may not be embedded.")
+    }
+}
+
+/**
+ * Return `true` if the [setLaunchingActivityStack] APIs is supported and can be used
+ * to set the launching [ActivityStack]. Otherwise, return `false`.
+ */
+@ExperimentalWindowApi
+fun ActivityOptions.isSetLaunchingActivityStackSupported(): Boolean {
+    return ExtensionsUtil.safeVendorApiLevel >= WindowExtensions.VENDOR_API_LEVEL_3
+}
diff --git a/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt b/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
index 59b0839..ba9f8a9 100644
--- a/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ActivityStack.kt
@@ -16,6 +16,7 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.os.IBinder
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
 
@@ -40,7 +41,11 @@
      * process(es), [activitiesInProcess] will return an empty list, but this method will return
      * `false`.
      */
-    val isEmpty: Boolean
+    val isEmpty: Boolean,
+    /**
+     * A token uniquely identifying this `ActivityStack`.
+     */
+    internal val token: IBinder,
 ) {
 
     /**
@@ -56,6 +61,7 @@
 
         if (activitiesInProcess != other.activitiesInProcess) return false
         if (isEmpty != other.isEmpty) return false
+        if (token != other.token) return false
 
         return true
     }
@@ -63,6 +69,7 @@
     override fun hashCode(): Int {
         var result = activitiesInProcess.hashCode()
         result = 31 * result + isEmpty.hashCode()
+        result = 31 * result + token.hashCode()
         return result
     }
 
@@ -70,5 +77,6 @@
         "ActivityStack{" +
             "activitiesInProcess=$activitiesInProcess" +
             ", isEmpty=$isEmpty" +
+            ", token=$token" +
             "}"
 }
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
index 3340a8b..ce56396 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
@@ -20,10 +20,10 @@
 import android.app.Activity
 import android.content.Context
 import android.content.Intent
+import android.os.Binder
 import android.util.LayoutDirection
 import android.util.Pair as AndroidPair
 import android.view.WindowMetrics
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.core.ExtensionsUtil
 import androidx.window.core.PredicateAdapter
 import androidx.window.embedding.SplitAttributes.LayoutDirection.Companion.BOTTOM_TO_TOP
@@ -56,7 +56,6 @@
 import androidx.window.extensions.embedding.SplitPlaceholderRule.Builder as SplitPlaceholderRuleBuilder
 import androidx.window.layout.WindowMetricsCalculator
 import androidx.window.layout.adapter.extensions.ExtensionsWindowLayoutInfoAdapter
-import kotlin.Pair
 
 /**
  * Adapter class that translates data classes between Extension and Jetpack interfaces.
@@ -82,13 +81,16 @@
                 SplitInfo(
                     ActivityStack(
                         primaryActivityStack.activities,
-                        primaryActivityStack.isEmpty
+                        primaryActivityStack.isEmpty,
+                        primaryActivityStack.token,
                     ),
                     ActivityStack(
                         secondaryActivityStack.activities,
-                        secondaryActivityStack.isEmpty
+                        secondaryActivityStack.isEmpty,
+                        secondaryActivityStack.token,
                     ),
-                    translate(splitInfo.splitAttributes)
+                    translate(splitInfo.splitAttributes),
+                    splitInfo.token,
                 )
             }
         }
@@ -117,14 +119,12 @@
             )
             .build()
 
-    @OptIn(ExperimentalWindowApi::class)
     fun translateSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ): Function<OEMSplitAttributesCalculatorParams, OEMSplitAttributes> = Function { oemParams ->
             translateSplitAttributes(calculator.invoke(translate(oemParams)))
         }
 
-    @OptIn(ExperimentalWindowApi::class)
     @SuppressLint("NewApi")
     fun translate(
         params: OEMSplitAttributesCalculatorParams
@@ -322,18 +322,21 @@
             val primaryActivityStack = splitInfo.primaryActivityStack
             val primaryFragment = ActivityStack(
                 primaryActivityStack.activities,
-                primaryActivityStack.isEmpty
+                primaryActivityStack.isEmpty,
+                INVALID_ACTIVITY_STACK_TOKEN,
             )
 
             val secondaryActivityStack = splitInfo.secondaryActivityStack
             val secondaryFragment = ActivityStack(
                 secondaryActivityStack.activities,
-                secondaryActivityStack.isEmpty
+                secondaryActivityStack.isEmpty,
+                INVALID_ACTIVITY_STACK_TOKEN,
             )
             return SplitInfo(
                 primaryFragment,
                 secondaryFragment,
-                translate(splitInfo.splitAttributes)
+                translate(splitInfo.splitAttributes),
+                INVALID_SPLIT_INFO_TOKEN,
             )
         }
     }
@@ -501,12 +504,28 @@
                 ActivityStack(
                     splitInfo.primaryActivityStack.activities,
                     splitInfo.primaryActivityStack.isEmpty,
+                    INVALID_ACTIVITY_STACK_TOKEN,
                 ),
                 ActivityStack(
                     splitInfo.secondaryActivityStack.activities,
                     splitInfo.secondaryActivityStack.isEmpty,
+                    INVALID_ACTIVITY_STACK_TOKEN,
                 ),
                 getSplitAttributesCompat(splitInfo),
+                INVALID_SPLIT_INFO_TOKEN,
             )
     }
+
+    internal companion object {
+        /**
+         * The default token of [SplitInfo], which provides compatibility for device prior to
+         * [WindowExtensions.VENDOR_API_LEVEL_3]
+         */
+        val INVALID_SPLIT_INFO_TOKEN = Binder()
+        /**
+         * The default token of [ActivityStack], which provides compatibility for device prior to
+         * [WindowExtensions.VENDOR_API_LEVEL_3]
+         */
+        val INVALID_ACTIVITY_STACK_TOKEN = Binder()
+    }
 }
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
index 02b8a67..c8825c0 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingBackend.kt
@@ -17,10 +17,11 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.app.ActivityOptions
 import android.content.Context
+import android.os.IBinder
 import androidx.annotation.RestrictTo
 import androidx.core.util.Consumer
-import androidx.window.core.ExperimentalWindowApi
 import java.util.concurrent.Executor
 
 /**
@@ -50,7 +51,6 @@
 
     fun isActivityEmbedded(activity: Activity): Boolean
 
-    @ExperimentalWindowApi
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     )
@@ -59,6 +59,20 @@
 
     fun isSplitAttributesCalculatorSupported(): Boolean
 
+    fun getActivityStack(activity: Activity): ActivityStack?
+
+    fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
+
+    fun finishActivityStacks(activityStacks: Set<ActivityStack>)
+
+    fun isFinishActivityStacksSupported(): Boolean
+
+    fun invalidateTopVisibleSplitAttributes()
+
+    fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
+
+    fun areSplitAttributesUpdatesSupported(): Boolean
+
     companion object {
 
         private var decorator: (EmbeddingBackend) -> EmbeddingBackend =
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
index d54b21a..a3559bb 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingCompat.kt
@@ -17,16 +17,18 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.app.ActivityOptions
 import android.content.Context
+import android.os.IBinder
 import android.util.Log
 import androidx.window.core.BuildConfig
 import androidx.window.core.ConsumerAdapter
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.core.ExtensionsUtil
 import androidx.window.core.VerificationMode
 import androidx.window.embedding.EmbeddingInterfaceCompat.EmbeddingCallbackInterface
 import androidx.window.embedding.SplitController.SplitSupportStatus.Companion.SPLIT_AVAILABLE
 import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_2
+import androidx.window.extensions.WindowExtensions.VENDOR_API_LEVEL_3
 import androidx.window.extensions.WindowExtensionsProvider
 import androidx.window.extensions.core.util.function.Consumer
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent
@@ -90,7 +92,6 @@
         return embeddingExtension.isActivityEmbedded(activity)
     }
 
-    @ExperimentalWindowApi
     override fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -114,6 +115,50 @@
     override fun isSplitAttributesCalculatorSupported(): Boolean =
         ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_2
 
+    override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
+        if (!isFinishActivityStacksSupported()) {
+            throw UnsupportedOperationException("#finishActivityStacks is not " +
+                "supported on the device.")
+        }
+        val stackTokens = activityStacks.mapTo(mutableSetOf()) { it.token }
+        embeddingExtension.finishActivityStacks(stackTokens)
+    }
+
+    override fun isFinishActivityStacksSupported(): Boolean =
+        ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
+
+    override fun invalidateTopVisibleSplitAttributes() {
+        if (!areSplitAttributesUpdatesSupported()) {
+            throw UnsupportedOperationException("#invalidateTopVisibleSplitAttributes is not " +
+                "supported on the device.")
+        }
+        embeddingExtension.invalidateTopVisibleSplitAttributes()
+    }
+
+    override fun updateSplitAttributes(
+        splitInfo: SplitInfo,
+        splitAttributes: SplitAttributes
+    ) {
+        if (!areSplitAttributesUpdatesSupported()) {
+            throw UnsupportedOperationException("#updateSplitAttributes is not supported on the " +
+                "device.")
+        }
+        embeddingExtension.updateSplitAttributes(
+            splitInfo.token,
+            adapter.translateSplitAttributes(splitAttributes)
+        )
+    }
+
+    override fun areSplitAttributesUpdatesSupported(): Boolean =
+        ExtensionsUtil.safeVendorApiLevel >= VENDOR_API_LEVEL_3
+
+    override fun setLaunchingActivityStack(
+        options: ActivityOptions,
+        token: IBinder
+    ): ActivityOptions {
+        return embeddingExtension.setLaunchingActivityStack(options, token)
+    }
+
     companion object {
         const val DEBUG = true
         private const val TAG = "EmbeddingCompat"
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
index c9830a5..26d8846 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingInterfaceCompat.kt
@@ -17,7 +17,8 @@
 package androidx.window.embedding
 
 import android.app.Activity
-import androidx.window.core.ExperimentalWindowApi
+import android.app.ActivityOptions
+import android.os.IBinder
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent
 
 /**
@@ -36,7 +37,6 @@
 
     fun isActivityEmbedded(activity: Activity): Boolean
 
-    @ExperimentalWindowApi
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     )
@@ -44,4 +44,16 @@
     fun clearSplitAttributesCalculator()
 
     fun isSplitAttributesCalculatorSupported(): Boolean
+
+    fun setLaunchingActivityStack(options: ActivityOptions, token: IBinder): ActivityOptions
+
+    fun finishActivityStacks(activityStacks: Set<ActivityStack>)
+
+    fun isFinishActivityStacksSupported(): Boolean
+
+    fun invalidateTopVisibleSplitAttributes()
+
+    fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes)
+
+    fun areSplitAttributesUpdatesSupported(): Boolean
 }
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
index d8371b7..9a931db 100644
--- a/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
+++ b/window/window/src/main/java/androidx/window/embedding/ExtensionEmbeddingBackend.kt
@@ -17,9 +17,11 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.app.ActivityOptions
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.Build
+import android.os.IBinder
 import android.util.Log
 import androidx.annotation.DoNotInline
 import androidx.annotation.GuardedBy
@@ -30,7 +32,6 @@
 import androidx.window.WindowProperties
 import androidx.window.core.BuildConfig
 import androidx.window.core.ConsumerAdapter
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.core.ExtensionsUtil
 import androidx.window.core.PredicateAdapter
 import androidx.window.core.VerificationMode
@@ -335,7 +336,6 @@
         return embeddingExtension?.isActivityEmbedded(activity) ?: false
     }
 
-    @ExperimentalWindowApi
     override fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -353,6 +353,49 @@
     override fun isSplitAttributesCalculatorSupported(): Boolean =
         embeddingExtension?.isSplitAttributesCalculatorSupported() ?: false
 
+    override fun getActivityStack(activity: Activity): ActivityStack? {
+        globalLock.withLock {
+            val lastInfo: List<SplitInfo> = splitInfoEmbeddingCallback.lastInfo ?: return null
+            for (info in lastInfo) {
+                if (activity !in info) {
+                    continue
+                }
+                if (activity in info.primaryActivityStack) {
+                    return info.primaryActivityStack
+                }
+                if (activity in info.secondaryActivityStack) {
+                    return info.secondaryActivityStack
+                }
+            }
+            return null
+        }
+    }
+
+    override fun setLaunchingActivityStack(
+        options: ActivityOptions,
+        token: IBinder
+    ): ActivityOptions = embeddingExtension?.setLaunchingActivityStack(options, token) ?: options
+
+    override fun finishActivityStacks(activityStacks: Set<ActivityStack>) {
+        embeddingExtension?.finishActivityStacks(activityStacks)
+    }
+
+    override fun isFinishActivityStacksSupported(): Boolean =
+        embeddingExtension?.isFinishActivityStacksSupported() ?: false
+
+    override fun invalidateTopVisibleSplitAttributes() {
+        embeddingExtension?.invalidateTopVisibleSplitAttributes()
+    }
+
+    override fun updateSplitAttributes(
+        splitInfo: SplitInfo,
+        splitAttributes: SplitAttributes
+    ) {
+        embeddingExtension?.updateSplitAttributes(splitInfo, splitAttributes)
+    }
+
+    override fun areSplitAttributesUpdatesSupported(): Boolean =
+        embeddingExtension?.areSplitAttributesUpdatesSupported() ?: false
     @RequiresApi(31)
     private object Api31Impl {
         @DoNotInline
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitAttributesCalculatorParams.kt b/window/window/src/main/java/androidx/window/embedding/SplitAttributesCalculatorParams.kt
index 8da62c6..40453be 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitAttributesCalculatorParams.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitAttributesCalculatorParams.kt
@@ -18,7 +18,6 @@
 
 import android.content.res.Configuration
 import androidx.annotation.RestrictTo
-import androidx.window.core.ExperimentalWindowApi
 import androidx.window.layout.WindowLayoutInfo
 import androidx.window.layout.WindowMetrics
 
@@ -27,7 +26,6 @@
  * [SplitController.setSplitAttributesCalculator] and references the corresponding [SplitRule] by
  * [splitRuleTag] if [SplitPairRule.tag] is specified.
  */
-@ExperimentalWindowApi
 class SplitAttributesCalculatorParams @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) constructor(
     /** The parent container's [WindowMetrics] */
     val parentWindowMetrics: WindowMetrics,
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitController.kt b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
index 41f46b8..660b15b 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitController.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitController.kt
@@ -155,9 +155,8 @@
      * example, a foldable device with multiple screens can choose to collapse
      * splits when apps run on the device's small display, but enable splits
      * when apps run on the device's large display. In cases like this,
-     * [splitSupportStatus] always returns [SplitSupportStatus.SPLIT_AVAILABLE], and if the
-     * split is collapsed, activities are launched on top, following the non-activity
-     * embedding model.
+     * [splitSupportStatus] always returns [SplitSupportStatus.SPLIT_AVAILABLE], and if the split is
+     * collapsed, activities are launched on top, following the non-activity embedding model.
      *
      * Also the [androidx.window.WindowProperties.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED]
      * must be enabled in AndroidManifest within <application> in order to get the correct
@@ -213,7 +212,6 @@
      * @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
      * `false`
      */
-    @ExperimentalWindowApi
     fun setSplitAttributesCalculator(
         calculator: (SplitAttributesCalculatorParams) -> SplitAttributes
     ) {
@@ -227,19 +225,85 @@
      * @throws UnsupportedOperationException if [isSplitAttributesCalculatorSupported] reports
      * `false`
      */
-    @ExperimentalWindowApi
     fun clearSplitAttributesCalculator() {
         embeddingBackend.clearSplitAttributesCalculator()
     }
 
     /** Returns whether [setSplitAttributesCalculator] is supported or not. */
-    @ExperimentalWindowApi
     fun isSplitAttributesCalculatorSupported(): Boolean =
         embeddingBackend.isSplitAttributesCalculatorSupported()
 
     /**
+     * Triggers a [SplitAttributes] update callback for the current topmost and visible split layout
+     * if there is one. This method can be used when a change to the split presentation originates
+     * from an application state change. Changes that are driven by parent window changes or new
+     * activity starts invoke the callback provided in [setSplitAttributesCalculator] automatically
+     * without the need to call this function.
+     *
+     * The top [SplitInfo] is usually the last element of [SplitInfo] list which was received from
+     * the callback registered in [SplitController.addSplitListener].
+     *
+     * The call will be ignored if there is no visible split.
+     *
+     * @throws UnsupportedOperationException if the device doesn't support this API.
+     */
+    @ExperimentalWindowApi
+    fun invalidateTopVisibleSplitAttributes() =
+        embeddingBackend.invalidateTopVisibleSplitAttributes()
+
+    /**
+     * Checks whether [invalidateTopVisibleSplitAttributes] is supported on the device.
+     *
+     * Invoking these APIs if the feature is not supported would trigger an
+     * [UnsupportedOperationException].
+     * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
+     * called safely, `false` otherwise.
+     */
+    @ExperimentalWindowApi
+    fun isInvalidatingTopVisibleSplitAttributesSupported(): Boolean =
+        embeddingBackend.areSplitAttributesUpdatesSupported()
+
+    /**
+     * Updates the [SplitAttributes] of a split pair. This is an alternative to using
+     * a split attributes calculator callback set in [setSplitAttributesCalculator], useful when
+     * apps only need to update the splits in a few cases proactively but rely on the default split
+     * attributes most of the time otherwise.
+     *
+     * The provided split attributes will be used instead of the associated
+     * [SplitRule.defaultSplitAttributes].
+     *
+     * **Note** that the split attributes may be updated if split attributes calculator callback is
+     * registered and invoked. If [setSplitAttributesCalculator] is used, the callback will still be
+     * applied to each [SplitInfo] when there's either:
+     * - A new Activity being launched.
+     * - A window or device state updates (e,g. due to screen rotation or folding state update).
+     *
+     * In most cases it is suggested to use [invalidateTopVisibleSplitAttributes] if
+     * [SplitAttributes] calculator callback is used.
+     *
+     * @param splitInfo the split pair to update
+     * @param splitAttributes the [SplitAttributes] to be applied
+     * @throws UnsupportedOperationException if this device doesn't support this API
+     */
+    @ExperimentalWindowApi
+    fun updateSplitAttributes(splitInfo: SplitInfo, splitAttributes: SplitAttributes) =
+        embeddingBackend.updateSplitAttributes(splitInfo, splitAttributes)
+
+    /**
+     * Checks whether [updateSplitAttributes] is supported on the device.
+     *
+     * Invoking these APIs if the feature is not supported would trigger an
+     * [UnsupportedOperationException].
+     * @return `true` if the runtime APIs to update [SplitAttributes] are supported and can be
+     * called safely, `false` otherwise.
+     */
+    @ExperimentalWindowApi
+    fun isUpdatingSplitAttributesSupported(): Boolean =
+        embeddingBackend.areSplitAttributesUpdatesSupported()
+
+    /**
      * A class to determine if activity splits with Activity Embedding are currently available.
-     * "Depending on the split property declaration, device software version or user preferences
+     * Depending on the split property declaration, device software version or user preferences
      * the feature might not be available.
      */
     class SplitSupportStatus private constructor(private val rawValue: Int) {
@@ -291,4 +355,4 @@
             return SplitController(backend)
         }
     }
-}
+}
\ No newline at end of file
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt b/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
index f366ca7..81adda5 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitInfo.kt
@@ -17,6 +17,7 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.os.IBinder
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
 
@@ -31,7 +32,11 @@
      */
     val secondaryActivityStack: ActivityStack,
     /** The [SplitAttributes] of this split pair. */
-    val splitAttributes: SplitAttributes
+    val splitAttributes: SplitAttributes,
+    /**
+     * A token uniquely identifying this `SplitInfo`.
+     */
+    internal val token: IBinder,
 ) {
     /**
      * Whether the [primaryActivityStack] or the [secondaryActivityStack] in this [SplitInfo]
@@ -49,6 +54,7 @@
         if (primaryActivityStack != other.primaryActivityStack) return false
         if (secondaryActivityStack != other.secondaryActivityStack) return false
         if (splitAttributes != other.splitAttributes) return false
+        if (token != other.token) return false
 
         return true
     }
@@ -57,6 +63,7 @@
         var result = primaryActivityStack.hashCode()
         result = 31 * result + secondaryActivityStack.hashCode()
         result = 31 * result + splitAttributes.hashCode()
+        result = 31 * result + token.hashCode()
         return result
     }
 
@@ -66,6 +73,7 @@
             append("primaryActivityStack=$primaryActivityStack, ")
             append("secondaryActivityStack=$secondaryActivityStack, ")
             append("splitAttributes=$splitAttributes, ")
+            append("token=$token")
             append("}")
         }
     }
diff --git a/window/window/src/main/java/androidx/window/embedding/SplitRule.kt b/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
index c989e32..a69cebc 100644
--- a/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
+++ b/window/window/src/main/java/androidx/window/embedding/SplitRule.kt
@@ -22,14 +22,13 @@
 import android.view.WindowMetrics
 import androidx.annotation.DoNotInline
 import androidx.annotation.IntRange
-import androidx.annotation.OptIn
 import androidx.annotation.RequiresApi
-import androidx.core.os.BuildCompat
 import androidx.core.util.Preconditions
 import androidx.window.embedding.EmbeddingAspectRatio.Companion.ALWAYS_ALLOW
 import androidx.window.embedding.EmbeddingAspectRatio.Companion.ratio
 import androidx.window.embedding.SplitRule.Companion.SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT
 import androidx.window.embedding.SplitRule.Companion.SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT
+import androidx.window.embedding.SplitRule.Companion.SPLIT_MIN_DIMENSION_ALWAYS_ALLOW
 import androidx.window.embedding.SplitRule.Companion.SPLIT_MIN_DIMENSION_DP_DEFAULT
 import androidx.window.embedding.SplitRule.FinishBehavior.Companion.ADJACENT
 import kotlin.math.min
@@ -231,14 +230,11 @@
      * Verifies if the provided parent bounds satisfy the dimensions and aspect ratio requirements
      * to apply the rule.
      */
-    // TODO(b/265089843) remove after Build.VERSION_CODES.U released.
-    @OptIn(markerClass = [BuildCompat.PrereleaseSdkCheck::class])
     internal fun checkParentMetrics(context: Context, parentMetrics: WindowMetrics): Boolean {
         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
             return false
         }
         val bounds = Api30Impl.getBounds(parentMetrics)
-        // TODO(b/265089843) replace with Build.VERSION.SDK_INT >= Build.VERSION_CODES.U
         val density = context.resources.displayMetrics.density
         return checkParentBounds(density, bounds)
     }
diff --git a/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculator.kt b/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculator.kt
index 94dd455..132ff58 100644
--- a/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculator.kt
+++ b/window/window/src/main/java/androidx/window/layout/WindowMetricsCalculator.kt
@@ -20,12 +20,14 @@
 import android.content.Context
 import android.inputmethodservice.InputMethodService
 import android.os.Build
+import android.util.DisplayMetrics
 import android.view.Display
 import android.view.WindowMetrics as AndroidWindowMetrics
 import androidx.annotation.RequiresApi
 import androidx.annotation.RestrictTo
 import androidx.annotation.UiContext
 import androidx.core.view.WindowInsetsCompat
+import androidx.window.core.Bounds
 
 /**
  * An interface to calculate the [WindowMetrics] for an [Activity] or a [UiContext].
@@ -153,6 +155,13 @@
                 windowMetrics.bounds,
                 WindowInsetsCompat.toWindowInsetsCompat(windowMetrics.windowInsets)
             )
+
+        internal fun fromDisplayMetrics(displayMetrics: DisplayMetrics): WindowMetrics {
+            return WindowMetrics(
+                    Bounds(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels),
+                    WindowInsetsCompat.Builder().build()
+                )
+        }
     }
 }
 
diff --git a/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt b/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt
index 326486e..ed8b7ee 100644
--- a/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt
+++ b/window/window/src/main/java/androidx/window/reflection/ReflectionUtils.kt
@@ -80,4 +80,16 @@
     internal fun Method.doesReturn(clazz: Class<*>): Boolean {
         return returnType.equals(clazz)
     }
-}
\ No newline at end of file
+
+    internal fun validateImplementation(
+        implementation: Class<*>,
+        requirements: Class<*>,
+    ): Boolean {
+        return requirements.methods.all {
+            validateReflection("${implementation.name}#${it.name} is not valid") {
+                val implementedMethod = implementation.getMethod(it.name, *it.parameterTypes)
+                implementedMethod.isPublic && implementedMethod.doesReturn(it.returnType)
+            }
+        }
+    }
+}
diff --git a/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt b/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt
index 341e019..b86fdc1 100644
--- a/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt
+++ b/window/window/src/main/java/androidx/window/reflection/WindowExtensionsConstants.kt
@@ -53,6 +53,27 @@
         "$WINDOW_EXTENSIONS_PACKAGE_NAME.layout.WindowLayoutComponent"
 
     /**
+     * Constant name for class [androidx.window.extensions.area.WindowAreaComponent]
+     * used for reflection
+     */
+    internal const val WINDOW_AREA_COMPONENT_CLASS =
+        "$WINDOW_EXTENSIONS_PACKAGE_NAME.area.WindowAreaComponent"
+
+    /**
+     * Constant name for class [androidx.window.extensions.area.ExtensionWindowAreaStatus]
+     * used for reflection
+     */
+    internal const val EXTENSION_WINDOW_AREA_STATUS_CLASS =
+        "$WINDOW_EXTENSIONS_PACKAGE_NAME.area.ExtensionWindowAreaStatus"
+
+    /**
+     * Constant name for class [androidx.window.extensions.area.ExtensionWindowAreaPresentation]
+     * used for reflection
+     */
+    internal const val EXTENSION_WINDOW_AREA_PRESENTATION_CLASS =
+        "$WINDOW_EXTENSIONS_PACKAGE_NAME.area.ExtensionWindowAreaPresentation"
+
+    /**
      * Constant name for class [androidx.window.extensions.embedding.ActivityEmbeddingComponent]
      * used for reflection
      */
diff --git a/window/window/src/test/java/androidx/window/area/WindowAreaAdapterUnitTest.kt b/window/window/src/test/java/androidx/window/area/WindowAreaAdapterUnitTest.kt
deleted file mode 100644
index 89a9808..0000000
--- a/window/window/src/test/java/androidx/window/area/WindowAreaAdapterUnitTest.kt
+++ /dev/null
@@ -1,49 +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.window.area
-
-import androidx.window.core.ExperimentalWindowApi
-import androidx.window.extensions.area.WindowAreaComponent
-import org.junit.Test
-
-/**
- * Unit tests for [WindowAreaAdapter] that run on the JVM.
- */
-@OptIn(ExperimentalWindowApi::class)
-class WindowAreaAdapterUnitTest {
-
-    @Test
-    fun testWindowAreaStatusTranslateValueAvailable() {
-        val expected = WindowAreaStatus.AVAILABLE
-        val translateValue = WindowAreaAdapter.translate(WindowAreaComponent.STATUS_AVAILABLE)
-        assert(expected == translateValue)
-    }
-
-    @Test
-    fun testWindowAreaStatusTranslateValueUnavailable() {
-        val expected = WindowAreaStatus.UNAVAILABLE
-        val translateValue = WindowAreaAdapter.translate(WindowAreaComponent.STATUS_UNAVAILABLE)
-        assert(expected == translateValue)
-    }
-
-    @Test
-    fun testWindowAreaStatusTranslateValueUnsupported() {
-        val expected = WindowAreaStatus.UNSUPPORTED
-        val translateValue = WindowAreaAdapter.translate(WindowAreaComponent.STATUS_UNSUPPORTED)
-        assert(expected == translateValue)
-    }
-}
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt b/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
index b13af0c..1f84586 100644
--- a/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/ActivityStackTest.kt
@@ -17,7 +17,9 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.os.Binder
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
 import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.mockito.kotlin.mock
@@ -27,7 +29,7 @@
     @Test
     fun testContainsActivity() {
         val activity = mock<Activity>()
-        val stack = ActivityStack(listOf(activity), isEmpty = false)
+        val stack = ActivityStack(listOf(activity), isEmpty = false, Binder())
 
         assertTrue(activity in stack)
     }
@@ -35,10 +37,17 @@
     @Test
     fun testEqualsImpliesHashCode() {
         val activity = mock<Activity>()
-        val first = ActivityStack(listOf(activity), isEmpty = false)
-        val second = ActivityStack(listOf(activity), isEmpty = false)
+        val token = Binder()
+        val first = ActivityStack(listOf(activity), isEmpty = false, token)
+        val second = ActivityStack(listOf(activity), isEmpty = false, token)
 
         assertEquals(first, second)
         assertEquals(first.hashCode(), second.hashCode())
+
+        val anotherToken = Binder()
+        val third = ActivityStack(emptyList(), isEmpty = true, anotherToken)
+
+        assertNotEquals(first, third)
+        assertNotEquals(first.hashCode(), third.hashCode())
     }
 }
\ No newline at end of file
diff --git a/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt b/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
index 3ad6e58..e297829 100644
--- a/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/SplitControllerTest.kt
@@ -45,9 +45,10 @@
     @Test
     fun test_splitInfoListComesFromBackend() = testScope.runTest {
         val expected = listOf(SplitInfo(
-            ActivityStack(emptyList(), true),
-            ActivityStack(emptyList(), true),
-            SplitAttributes()
+            ActivityStack(emptyList(), true, mock()),
+            ActivityStack(emptyList(), true, mock()),
+            SplitAttributes(),
+            mock()
         ))
         doAnswer { invocationOnMock ->
             @Suppress("UNCHECKED_CAST")
diff --git a/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt b/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
index 07c0855..780bcf9 100644
--- a/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
+++ b/window/window/src/test/java/androidx/window/embedding/SplitInfoTest.kt
@@ -17,6 +17,9 @@
 package androidx.window.embedding
 
 import android.app.Activity
+import android.os.Binder
+import android.os.IBinder
+import androidx.window.embedding.EmbeddingAdapter.Companion.INVALID_ACTIVITY_STACK_TOKEN
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
 import org.junit.Test
@@ -30,7 +33,8 @@
         val firstStack = createTestActivityStack(listOf(activity))
         val secondStack = createTestActivityStack(emptyList())
         val attributes = SplitAttributes()
-        val info = SplitInfo(firstStack, secondStack, attributes)
+        val token = Binder()
+        val info = SplitInfo(firstStack, secondStack, attributes, token)
 
         assertTrue(info.contains(activity))
     }
@@ -41,7 +45,8 @@
         val firstStack = createTestActivityStack(emptyList())
         val secondStack = createTestActivityStack(listOf(activity))
         val attributes = SplitAttributes()
-        val info = SplitInfo(firstStack, secondStack, attributes)
+        val token = Binder()
+        val info = SplitInfo(firstStack, secondStack, attributes, token)
 
         assertTrue(info.contains(activity))
     }
@@ -52,8 +57,9 @@
         val firstStack = createTestActivityStack(emptyList())
         val secondStack = createTestActivityStack(listOf(activity))
         val attributes = SplitAttributes()
-        val firstInfo = SplitInfo(firstStack, secondStack, attributes)
-        val secondInfo = SplitInfo(firstStack, secondStack, attributes)
+        val token = Binder()
+        val firstInfo = SplitInfo(firstStack, secondStack, attributes, token)
+        val secondInfo = SplitInfo(firstStack, secondStack, attributes, token)
 
         assertEquals(firstInfo, secondInfo)
         assertEquals(firstInfo.hashCode(), secondInfo.hashCode())
@@ -62,5 +68,6 @@
     private fun createTestActivityStack(
         activitiesInProcess: List<Activity>,
         isEmpty: Boolean = false,
-    ): ActivityStack = ActivityStack(activitiesInProcess, isEmpty)
+        token: IBinder = INVALID_ACTIVITY_STACK_TOKEN,
+    ): ActivityStack = ActivityStack(activitiesInProcess, isEmpty, token)
 }
\ No newline at end of file
diff --git a/window/window/src/test/resources/robolectric.properties b/window/window/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..69fde47
--- /dev/null
+++ b/window/window/src/test/resources/robolectric.properties
@@ -0,0 +1,3 @@
+# robolectric properties
+# Temporary until we update Robolectric to support API level 34.
+sdk=33
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpecDao.kt b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpecDao.kt
index 425b19e..86d643c 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpecDao.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/model/WorkSpecDao.kt
@@ -88,6 +88,7 @@
     @Transaction
     @Query("SELECT id FROM workspec")
     fun getAllWorkSpecIdsLiveData(): LiveData<List<String>>
+
     /**
      * Updates the state of at least one [WorkSpec] by ID.
      *
@@ -141,13 +142,26 @@
     fun resetWorkSpecRunAttemptCount(id: String): Int
 
     /**
+     * Updates the next schedule time of a [WorkSpec].
+     *
+     * @param id The [WorkSpec] identifier to update
+     * @param nextScheduleTimeOverrideMillis The next schedule time in millis since epoch. See
+     * [WorkSpec.nextScheduleTimeOverride]
+     */
+    @Query("UPDATE workspec SET next_schedule_time_override=:nextScheduleTimeOverrideMillis " +
+        "WHERE id=:id")
+    fun setNextScheduleTimeOverride(id: String, nextScheduleTimeOverrideMillis: Long)
+
+    /**
      * Resets the next schedule time override of a [WorkSpec] if the override generation has not
      * changed.
      *
      * @param id The identifier for the [WorkSpec]
      */
-    @Query("UPDATE workspec SET next_schedule_time_override=${Long.MAX_VALUE} WHERE " +
-        "(id=:id AND next_schedule_time_override_generation=:overrideGeneration)")
+    @Query(
+        "UPDATE workspec SET next_schedule_time_override=${Long.MAX_VALUE} WHERE " +
+            "(id=:id AND next_schedule_time_override_generation=:overrideGeneration)"
+    )
     fun resetWorkSpecNextScheduleTimeOverride(id: String, overrideGeneration: Int)
 
     /**
@@ -292,7 +306,7 @@
      */
     @Query(
         "SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES +
-        " AND id IN (SELECT work_spec_id FROM worktag WHERE tag=:tag)"
+            " AND id IN (SELECT work_spec_id FROM worktag WHERE tag=:tag)"
     )
     fun getUnfinishedWorkWithTag(tag: String): List<String>
 
@@ -446,7 +460,8 @@
     @Update
     fun updateWorkSpec(workSpec: WorkSpec)
 
-    @Query("Select COUNT(*) FROM workspec WHERE LENGTH(content_uri_triggers)<>0" +
+    @Query(
+        "Select COUNT(*) FROM workspec WHERE LENGTH(content_uri_triggers)<>0" +
             " AND state NOT IN $COMPLETED_STATES"
     )
     fun countNonFinishedContentUriTriggerWorkers(): Int
diff --git a/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerTest.java b/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerTest.java
index 8e31393..cd27900 100644
--- a/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerTest.java
+++ b/work/work-testing/src/androidTest/java/androidx/work/testing/TestSchedulerTest.java
@@ -204,6 +204,60 @@
         assertThat(CountingTestWorker.COUNT.get(), is(2));
     }
 
+
+    @Test
+    public void testOverrideWorker_doesntRunYet() {
+        // No initialdelay. Generally a Periodic worker would run immediately.
+        PeriodicWorkRequest request = createNextScheduleOverrideWorkRequest();
+        WorkManager workManager = WorkManager.getInstance(mContext);
+        workManager.enqueue(request);
+
+        // Override behaves like periodic, so the first run still would have needed setPeriodMet()
+        assertThat(CountingTestWorker.COUNT.get(), is(0));
+    }
+
+    @Test
+    public void testOverrideWorker_firstRun_initialDelayMet_doesntRun() {
+        PeriodicWorkRequest request = createNextScheduleOverrideWorkRequestWithInitialDelay();
+        WorkManager workManager = WorkManager.getInstance(mContext);
+        workManager.enqueue(request);
+        // Override behaves like periodic, so meeting initialdelay does nothing.
+        mTestDriver.setInitialDelayMet(request.getId());
+        assertThat(CountingTestWorker.COUNT.get(), is(0));
+    }
+
+    @Test
+    public void testOverrideWorker_firstRun_periodDelayMet_runs()
+            throws InterruptedException, ExecutionException {
+        // Even with initialdelay, only .setPeriodMet() is needed to unblock.
+        PeriodicWorkRequest request = createNextScheduleOverrideWorkRequestWithInitialDelay();
+        WorkManager workManager = WorkManager.getInstance(mContext);
+        workManager.enqueue(request);
+        // Override behaves like periodic, so meeting initialdelay does nothing.
+        mTestDriver.setPeriodDelayMet(request.getId());
+        WorkInfo requestStatus = workManager.getWorkInfoById(request.getId()).get();
+        assertThat(CountingTestWorker.COUNT.get(), is(1));
+    }
+
+    @Test
+    public void testOverrideWorker_afterExpiring_periodDelayMetRuns()
+            throws ExecutionException, InterruptedException {
+        PeriodicWorkRequest request =
+                createNextScheduleOverrideWorkRequest();
+        WorkManager workManager = WorkManager.getInstance(mContext);
+        workManager.enqueue(request);
+        mTestDriver.setPeriodDelayMet(request.getId());
+        assertThat(CountingTestWorker.COUNT.get(), is(1));
+
+        // Subsequent periods (overrideMet has cleared) work normally
+        for (int i = 0; i < 5; ++i) {
+            mTestDriver.setPeriodDelayMet(request.getId());
+            assertThat(CountingTestWorker.COUNT.get(), is(i + 2));
+            WorkInfo requestStatus = workManager.getWorkInfoById(request.getId()).get();
+            assertThat(requestStatus.getState().isFinished(), is(false));
+        }
+    }
+
     @Test
     public void testWorker_withPeriodicWorkerFlex_shouldRun() {
         PeriodicWorkRequest request = createPeriodicWorkRequestWithFlex();
@@ -410,6 +464,18 @@
                 .build();
     }
 
+    private static PeriodicWorkRequest createNextScheduleOverrideWorkRequest() {
+        return new PeriodicWorkRequest.Builder(CountingTestWorker.class, 1L, TimeUnit.DAYS)
+                .setNextScheduleTimeOverride(TimeUnit.DAYS.toMillis(10))
+                .build();
+    }
+
+    private static PeriodicWorkRequest createNextScheduleOverrideWorkRequestWithInitialDelay() {
+        return new PeriodicWorkRequest.Builder(CountingTestWorker.class, 1L,
+                TimeUnit.DAYS).setInitialDelay(2L, TimeUnit.DAYS).setNextScheduleTimeOverride(
+                TimeUnit.DAYS.toMillis(10)).build();
+    }
+
     private static PeriodicWorkRequest createPeriodicWorkRequest() {
         return new PeriodicWorkRequest.Builder(CountingTestWorker.class, 10L, TimeUnit.DAYS)
                 .build();
diff --git a/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt b/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
index 5f8cfdc..f871ce7 100644
--- a/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
+++ b/work/work-testing/src/main/java/androidx/work/testing/TestScheduler.kt
@@ -174,7 +174,7 @@
             }
         } else {
             if (isRunnableInternalState(spec, state)) {
-                workDatabase.rewindLastEnqueueTimeIfNecessary(spec.id, clock)
+                workDatabase.rewindNextRunTimeToNow(spec.id, clock)
                 launcher.startWork(generateStartStopToken(spec, generationalId))
             }
             // Clock is not considered, only InternalWorkSpec.
@@ -212,6 +212,7 @@
         val initialDelay =
             spec.initialDelay == 0L || state.initialDelayMet || !spec.isFirstPeriodicRun
         val periodic =
+            // .isFirstPeriodicRun is false for overridden first periods.
             if (spec.isPeriodic) (state.periodDelayMet || spec.isFirstPeriodicRun) else true
         return state.isScheduled && constraints && periodic && initialDelay
     }
@@ -233,11 +234,15 @@
     val isScheduled: Boolean = false,
 )
 
-private val WorkSpec.isFirstPeriodicRun get() = periodCount == 0 && runAttemptCount == 0
+private val WorkSpec.isNextScheduleOverridden get() = nextScheduleTimeOverride != Long.MAX_VALUE
 
-private fun WorkDatabase.rewindLastEnqueueTimeIfNecessary(id: String, clock: Clock): WorkSpec {
+private val WorkSpec.isFirstPeriodicRun get() =
+    periodCount == 0 && runAttemptCount == 0 && !isNextScheduleOverridden
+        // Overrides are treated as continuing periods, not first runs.
+
+private fun WorkDatabase.rewindNextRunTimeToNow(id: String, clock: Clock): WorkSpec {
     // We need to pass check that mWorkSpec.calculateNextRunTime() < now
-    // so we reset "rewind" enqueue time to pass the check
+    // so we reset "rewind" enqueue time or nextScheduleTimeOverride to pass the check
     // we don't reuse available internalWorkState.mWorkSpec, because it
     // is not update with period_count and last_enqueue_time
     val dao: WorkSpecDao = workSpecDao()
@@ -246,7 +251,11 @@
     val now = clock.currentTimeMillis()
     val timeOffset = workSpec.calculateNextRunTime() - now
     if (timeOffset > 0) {
-        dao.setLastEnqueueTime(id, workSpec.lastEnqueueTime - timeOffset)
+        if (workSpec.isNextScheduleOverridden) {
+            dao.setNextScheduleTimeOverride(id, now)
+        } else {
+            dao.setLastEnqueueTime(id, workSpec.lastEnqueueTime - timeOffset)
+        }
     }
     return dao.getWorkSpec(id)
         ?: throw IllegalStateException("WorkSpec is already deleted from WM's db")