Merge "Fix LazyColumnTest.removeItemsTest" into androidx-main
diff --git a/activity/activity-ktx/api/current.ignore b/activity/activity-ktx/api/current.ignore
index d23680b..1b633a6 100644
--- a/activity/activity-ktx/api/current.ignore
+++ b/activity/activity-ktx/api/current.ignore
@@ -1,3 +1,7 @@
 // Baseline format: 1.0
 RemovedClass: androidx.activity.OnBackPressedDispatcherKt:
     Removed class androidx.activity.OnBackPressedDispatcherKt
+
+
+RemovedPackage: androidx.activity.contextaware:
+    Removed package androidx.activity.contextaware
diff --git a/activity/activity-ktx/api/current.txt b/activity/activity-ktx/api/current.txt
index ba9fdc3..a1c4a4d 100644
--- a/activity/activity-ktx/api/current.txt
+++ b/activity/activity-ktx/api/current.txt
@@ -11,14 +11,6 @@
 
 }
 
-package androidx.activity.contextaware {
-
-  public final class ContextAwareKt {
-    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R>);
-  }
-
-}
-
 package androidx.activity.result {
 
   public final class ActivityResultCallerKt {
diff --git a/activity/activity-ktx/api/public_plus_experimental_current.txt b/activity/activity-ktx/api/public_plus_experimental_current.txt
index cece293..980229c 100644
--- a/activity/activity-ktx/api/public_plus_experimental_current.txt
+++ b/activity/activity-ktx/api/public_plus_experimental_current.txt
@@ -12,14 +12,6 @@
 
 }
 
-package androidx.activity.contextaware {
-
-  public final class ContextAwareKt {
-    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R>);
-  }
-
-}
-
 package androidx.activity.result {
 
   public final class ActivityResultCallerKt {
diff --git a/activity/activity-ktx/api/restricted_current.ignore b/activity/activity-ktx/api/restricted_current.ignore
index d23680b..1b633a6 100644
--- a/activity/activity-ktx/api/restricted_current.ignore
+++ b/activity/activity-ktx/api/restricted_current.ignore
@@ -1,3 +1,7 @@
 // Baseline format: 1.0
 RemovedClass: androidx.activity.OnBackPressedDispatcherKt:
     Removed class androidx.activity.OnBackPressedDispatcherKt
+
+
+RemovedPackage: androidx.activity.contextaware:
+    Removed package androidx.activity.contextaware
diff --git a/activity/activity-ktx/api/restricted_current.txt b/activity/activity-ktx/api/restricted_current.txt
index ba9fdc3..a1c4a4d 100644
--- a/activity/activity-ktx/api/restricted_current.txt
+++ b/activity/activity-ktx/api/restricted_current.txt
@@ -11,14 +11,6 @@
 
 }
 
-package androidx.activity.contextaware {
-
-  public final class ContextAwareKt {
-    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R>);
-  }
-
-}
-
 package androidx.activity.result {
 
   public final class ActivityResultCallerKt {
diff --git a/activity/activity-ktx/src/androidTest/java/androidx/activity/contextaware/ContextAwareTest.kt b/activity/activity-ktx/src/androidTest/java/androidx/activity/contextaware/ContextAwareTest.kt
deleted file mode 100644
index d56602a..0000000
--- a/activity/activity-ktx/src/androidTest/java/androidx/activity/contextaware/ContextAwareTest.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2020 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.activity.contextaware
-
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ContextAwareTest {
-
-    @Test
-    fun alreadyAvailable() = runBlocking(Dispatchers.Main) {
-        val contextAware = TestContextAware()
-        contextAware.dispatchOnContextAvailable()
-        var result = "initial"
-        val receivedResult = contextAware.withContextAvailable {
-            result
-        }
-        result = "after"
-        assertThat(receivedResult).isEqualTo("initial")
-    }
-
-    @Test
-    fun suspending() = runBlocking(Dispatchers.Main) {
-        val contextAware = TestContextAware()
-        var result = "initial"
-        launch {
-            contextAware.dispatchOnContextAvailable()
-            result = "post dispatch"
-        }
-        val receivedResult = contextAware.withContextAvailable {
-            result
-        }
-        contextAware.addOnContextAvailableListener {
-            result = "after"
-        }
-        assertThat(receivedResult).isEqualTo("initial")
-    }
-}
-
-private class TestContextAware : ContextAware {
-    private val contextAwareHelper = ContextAwareHelper()
-
-    override fun peekAvailableContext() = contextAwareHelper.peekAvailableContext()
-
-    override fun addOnContextAvailableListener(listener: OnContextAvailableListener) {
-        contextAwareHelper.addOnContextAvailableListener(listener)
-    }
-
-    override fun removeOnContextAvailableListener(listener: OnContextAvailableListener) {
-        contextAwareHelper.removeOnContextAvailableListener(listener)
-    }
-
-    fun dispatchOnContextAvailable() {
-        contextAwareHelper.dispatchOnContextAvailable(
-            ApplicationProvider.getApplicationContext()
-        )
-    }
-}
diff --git a/activity/activity-ktx/src/main/java/androidx/activity/contextaware/ContextAware.kt b/activity/activity-ktx/src/main/java/androidx/activity/contextaware/ContextAware.kt
deleted file mode 100644
index 163820d..0000000
--- a/activity/activity-ktx/src/main/java/androidx/activity/contextaware/ContextAware.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2020 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.activity.contextaware
-
-import android.content.Context
-import kotlinx.coroutines.suspendCancellableCoroutine
-
-/**
- * Run [onContextAvailable] when the [Context] becomes available and
- * resume with the result.
- *
- * If the [Context] is already available, [onContextAvailable] will be
- * synchronously called on the current coroutine context. Otherwise,
- * [onContextAvailable] will be called on the UI thread immediately when
- * the Context becomes available.
- */
-public suspend inline fun <R> ContextAware.withContextAvailable(
-    crossinline onContextAvailable: (Context) -> R
-): R {
-    val availableContext = peekAvailableContext()
-    return if (availableContext != null) {
-        onContextAvailable(availableContext)
-    } else {
-        suspendCancellableCoroutine { co ->
-            val listener = object : OnContextAvailableListener {
-                override fun onContextAvailable(context: Context) {
-                    co.resumeWith(runCatching { onContextAvailable(context) })
-                }
-            }
-            addOnContextAvailableListener(listener)
-            co.invokeOnCancellation {
-                removeOnContextAvailableListener(listener)
-            }
-        }
-    }
-}
diff --git a/activity/activity/api/current.txt b/activity/activity/api/current.txt
index 688b1a0..bf98034 100644
--- a/activity/activity/api/current.txt
+++ b/activity/activity/api/current.txt
@@ -119,22 +119,26 @@
 package androidx.activity.contextaware {
 
   public interface ContextAware {
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
   public final class ContextAwareHelper {
     ctor public ContextAwareHelper();
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public void clearAvailableContext();
-    method public void dispatchOnContextAvailable(android.content.Context);
+    method public void dispatchOnContextAvailable(android.content.Context context);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
-  public interface OnContextAvailableListener {
-    method public void onContextAvailable(android.content.Context);
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<android.content.Context,R> onContextAvailable, kotlin.coroutines.Continuation<R>);
+  }
+
+  public fun interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context context);
   }
 
 }
diff --git a/activity/activity/api/public_plus_experimental_current.txt b/activity/activity/api/public_plus_experimental_current.txt
index 688b1a0..bf98034 100644
--- a/activity/activity/api/public_plus_experimental_current.txt
+++ b/activity/activity/api/public_plus_experimental_current.txt
@@ -119,22 +119,26 @@
 package androidx.activity.contextaware {
 
   public interface ContextAware {
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
   public final class ContextAwareHelper {
     ctor public ContextAwareHelper();
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public void clearAvailableContext();
-    method public void dispatchOnContextAvailable(android.content.Context);
+    method public void dispatchOnContextAvailable(android.content.Context context);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
-  public interface OnContextAvailableListener {
-    method public void onContextAvailable(android.content.Context);
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<android.content.Context,R> onContextAvailable, kotlin.coroutines.Continuation<R>);
+  }
+
+  public fun interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context context);
   }
 
 }
diff --git a/activity/activity/api/restricted_current.txt b/activity/activity/api/restricted_current.txt
index 1d24b8c..7561e11 100644
--- a/activity/activity/api/restricted_current.txt
+++ b/activity/activity/api/restricted_current.txt
@@ -118,22 +118,26 @@
 package androidx.activity.contextaware {
 
   public interface ContextAware {
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
   public final class ContextAwareHelper {
     ctor public ContextAwareHelper();
-    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
     method public void clearAvailableContext();
-    method public void dispatchOnContextAvailable(android.content.Context);
+    method public void dispatchOnContextAvailable(android.content.Context context);
     method public android.content.Context? peekAvailableContext();
-    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener listener);
   }
 
-  public interface OnContextAvailableListener {
-    method public void onContextAvailable(android.content.Context);
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<android.content.Context,R> onContextAvailable, kotlin.coroutines.Continuation<R>);
+  }
+
+  public fun interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context context);
   }
 
 }
diff --git a/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt b/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt
index e3bbb87..e579938 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/contextaware/ContextAwareHelperTest.kt
@@ -21,6 +21,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
 import leakcanary.DetectLeaksAfterTestSuccess
 import org.junit.Rule
 import org.junit.Test
@@ -110,6 +113,35 @@
 
         assertThat(callbackCount).isEqualTo(0)
     }
+
+    @Test
+    fun alreadyAvailable() = runBlocking(Dispatchers.Main) {
+        val contextAware = TestContextAware()
+        contextAware.dispatchOnContextAvailable()
+        var result = "initial"
+        val receivedResult = contextAware.withContextAvailable {
+            result
+        }
+        result = "after"
+        assertThat(receivedResult).isEqualTo("initial")
+    }
+
+    @Test
+    fun suspending() = runBlocking(Dispatchers.Main) {
+        val contextAware = TestContextAware()
+        var result = "initial"
+        launch {
+            contextAware.dispatchOnContextAvailable()
+            result = "post dispatch"
+        }
+        val receivedResult = contextAware.withContextAvailable {
+            result
+        }
+        contextAware.addOnContextAvailableListener {
+            result = "after"
+        }
+        assertThat(receivedResult).isEqualTo("initial")
+    }
 }
 
 class TestContextAware : ContextAware {
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java
deleted file mode 100644
index 4e0b4c7..0000000
--- a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2020 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.activity.contextaware;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * A <code>ContextAware</code> class is associated with a {@link Context} sometime after
- * the class is instantiated. By adding a {@link OnContextAvailableListener}, you can
- * receive a callback for that event.
- * <p>
- * Classes implementing {@link ContextAware} are strongly recommended to also implement
- * {@link androidx.lifecycle.LifecycleOwner} for providing a more general purpose API for
- * listening for creation and destruction events.
- *
- * @see ContextAwareHelper
- */
-public interface ContextAware {
-
-    /**
-     * Get the {@link Context} if it is currently available. If this returns
-     * <code>null</code>, you can use
-     * {@link #addOnContextAvailableListener(OnContextAvailableListener)} to receive
-     * a callback for when it available.
-     *
-     * @return the Context if it is currently available.
-     */
-    @Nullable
-    Context peekAvailableContext();
-
-    /**
-     * Add a new {@link OnContextAvailableListener} for receiving a callback for when
-     * this class is associated with a {@link android.content.Context}.
-     * <p>
-     * Listeners are triggered in the order they are added when added before the Context is
-     * available. Listeners added after the context has been made available will have the Context
-     * synchronously delivered to them as part of this call.
-     *
-     * @param listener The listener that should be added.
-     * @see #removeOnContextAvailableListener(OnContextAvailableListener)
-     */
-    void addOnContextAvailableListener(@NonNull OnContextAvailableListener listener);
-
-    /**
-     * Remove a {@link OnContextAvailableListener} previously added via
-     * {@link #addOnContextAvailableListener(OnContextAvailableListener)}.
-     *
-     * @param listener The listener that should be removed.
-     * @see #addOnContextAvailableListener(OnContextAvailableListener)
-     */
-    void removeOnContextAvailableListener(@NonNull OnContextAvailableListener listener);
-}
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.kt b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.kt
new file mode 100644
index 0000000..7f43714
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAware.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 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.activity.contextaware
+
+import android.content.Context
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+/**
+ * A `ContextAware` class is associated with a [Context] sometime after
+ * the class is instantiated. By adding a [OnContextAvailableListener], you can
+ * receive a callback for that event.
+ *
+ * Classes implementing [ContextAware] are strongly recommended to also implement
+ * [androidx.lifecycle.LifecycleOwner] for providing a more general purpose API for
+ * listening for creation and destruction events.
+ *
+ * @see ContextAwareHelper
+ */
+interface ContextAware {
+    /**
+     * Get the [Context] if it is currently available. If this returns
+     * `null`, you can use [addOnContextAvailableListener] to receive
+     * a callback for when it available.
+     *
+     * @return the Context if it is currently available.
+     */
+    fun peekAvailableContext(): Context?
+
+    /**
+     * Add a new [OnContextAvailableListener] for receiving a callback for when
+     * this class is associated with a [android.content.Context].
+     *
+     * Listeners are triggered in the order they are added when added before the Context is
+     * available. Listeners added after the context has been made available will have the Context
+     * synchronously delivered to them as part of this call.
+     *
+     * @param listener The listener that should be added.
+     * @see removeOnContextAvailableListener
+     */
+    fun addOnContextAvailableListener(listener: OnContextAvailableListener)
+
+    /**
+     * Remove a [OnContextAvailableListener] previously added via
+     * [addOnContextAvailableListener].
+     *
+     * @param listener The listener that should be removed.
+     * @see addOnContextAvailableListener
+     */
+    fun removeOnContextAvailableListener(listener: OnContextAvailableListener)
+}
+
+/**
+ * Run [onContextAvailable] when the [Context] becomes available and
+ * resume with the result.
+ *
+ * If the [Context] is already available, [onContextAvailable] will be
+ * synchronously called on the current coroutine context. Otherwise,
+ * [onContextAvailable] will be called on the UI thread immediately when
+ * the Context becomes available.
+ */
+suspend inline fun <R> ContextAware.withContextAvailable(
+    crossinline onContextAvailable: (@JvmSuppressWildcards Context) -> @JvmSuppressWildcards R
+): @JvmSuppressWildcards R {
+    val availableContext = peekAvailableContext()
+    return if (availableContext != null) {
+        onContextAvailable(availableContext)
+    } else {
+        suspendCancellableCoroutine { co ->
+            val listener = object : OnContextAvailableListener {
+                override fun onContextAvailable(context: Context) {
+                    co.resumeWith(runCatching { onContextAvailable(context) })
+                }
+            }
+            addOnContextAvailableListener(listener)
+            co.invokeOnCancellation {
+                removeOnContextAvailableListener(listener)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java
deleted file mode 100644
index c29b7a3..0000000
--- a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2020 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.activity.contextaware;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-/**
- * Helper class for implementing {@link ContextAware}. Classes using this helper should
- * call {@link #addOnContextAvailableListener(OnContextAvailableListener)} and
- * {@link #removeOnContextAvailableListener(OnContextAvailableListener)} as the respective
- * methods of {@link ContextAware} are called.
- * <p>
- * You must call {@link #dispatchOnContextAvailable(Context)} once the
- * {@link Context} is available to dispatch the callbacks to all registered listeners.
- * <p>
- * Listeners added after the context has been made available via
- * {@link #dispatchOnContextAvailable(Context)} will have the Context synchronously
- * delivered to them up until {@link #clearAvailableContext()} is called.
- */
-public final class ContextAwareHelper {
-
-    private final Set<OnContextAvailableListener> mListeners = new CopyOnWriteArraySet<>();
-
-    private volatile Context mContext;
-
-    /**
-     * Construct a new ContextAwareHelper.
-     */
-    public ContextAwareHelper() {
-    }
-
-    /**
-     * Get the {@link Context} if it is currently available. If this returns
-     * <code>null</code>, you can use
-     * {@link #addOnContextAvailableListener(OnContextAvailableListener)} to receive
-     * a callback for when it available.
-     *
-     * @return the Context if it is currently available.
-     */
-    @Nullable
-    public Context peekAvailableContext() {
-        return mContext;
-    }
-
-    /**
-     * Add a new {@link OnContextAvailableListener} for receiving a callback for when
-     * this class is associated with a {@link android.content.Context}.
-     *
-     * @param listener The listener that should be added.
-     * @see #removeOnContextAvailableListener(OnContextAvailableListener)
-     */
-    public void addOnContextAvailableListener(@NonNull OnContextAvailableListener listener) {
-        if (mContext != null) {
-            listener.onContextAvailable(mContext);
-        }
-        mListeners.add(listener);
-    }
-
-    /**
-     * Remove a {@link OnContextAvailableListener} previously added via
-     * {@link #addOnContextAvailableListener(OnContextAvailableListener)}.
-     *
-     * @param listener The listener that should be removed.
-     * @see #addOnContextAvailableListener(OnContextAvailableListener)
-     */
-    public void removeOnContextAvailableListener(@NonNull OnContextAvailableListener listener) {
-        mListeners.remove(listener);
-    }
-
-    /**
-     * Dispatch the callback of {@link OnContextAvailableListener#onContextAvailable} to
-     * all currently added listeners in the order they were added.
-     *
-     * @param context The {@link Context} the {@link ContextAware} object is now associated with.
-     */
-    public void dispatchOnContextAvailable(@NonNull Context context) {
-        mContext = context;
-        for (OnContextAvailableListener listener : mListeners) {
-            listener.onContextAvailable(context);
-        }
-    }
-
-    /**
-     * Clear any {@link Context} previously made available via
-     * {@link #dispatchOnContextAvailable(Context)}.
-     */
-    public void clearAvailableContext() {
-        mContext = null;
-    }
-}
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.kt b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.kt
new file mode 100644
index 0000000..0a76e42
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/ContextAwareHelper.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 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.activity.contextaware
+
+import android.content.Context
+import java.util.concurrent.CopyOnWriteArraySet
+
+/**
+ * Helper class for implementing [ContextAware]. Classes using this helper should
+ * call [addOnContextAvailableListener] and [removeOnContextAvailableListener] as the respective
+ * methods of [ContextAware] are called.
+ *
+ * You must call [dispatchOnContextAvailable] once the
+ * [Context] is available to dispatch the callbacks to all registered listeners.
+ *
+ * Listeners added after the context has been made available via
+ * [dispatchOnContextAvailable] will have the Context synchronously
+ * delivered to them up until [clearAvailableContext] is called.
+ */
+class ContextAwareHelper {
+    private val listeners: MutableSet<OnContextAvailableListener> = CopyOnWriteArraySet()
+
+    @Volatile
+    private var context: Context? = null
+
+    /**
+     * Get the [Context] if it is currently available. If this returns
+     * `null`, you can use [addOnContextAvailableListener] to receive
+     * a callback for when it available.
+     *
+     * @return the Context if it is currently available.
+     */
+    fun peekAvailableContext(): Context? {
+        return context
+    }
+
+    /**
+     * Add a new [OnContextAvailableListener] for receiving a callback for when
+     * this class is associated with a [android.content.Context].
+     *
+     * @param listener The listener that should be added.
+     * @see removeOnContextAvailableListener
+     */
+    fun addOnContextAvailableListener(listener: OnContextAvailableListener) {
+        context?.let {
+            listener.onContextAvailable(it)
+        }
+        listeners.add(listener)
+    }
+
+    /**
+     * Remove a [OnContextAvailableListener] previously added via
+     * [addOnContextAvailableListener].
+     *
+     * @param listener The listener that should be removed.
+     * @see addOnContextAvailableListener
+     */
+    fun removeOnContextAvailableListener(listener: OnContextAvailableListener) {
+        listeners.remove(listener)
+    }
+
+    /**
+     * Dispatch the callback of [OnContextAvailableListener.onContextAvailable] to
+     * all currently added listeners in the order they were added.
+     *
+     * @param context The [Context] the [ContextAware] object is now associated with.
+     */
+    fun dispatchOnContextAvailable(context: Context) {
+        this.context = context
+        for (listener in listeners) {
+            listener.onContextAvailable(context)
+        }
+    }
+
+    /**
+     * Clear any [Context] previously made available via
+     * [dispatchOnContextAvailable].
+     */
+    fun clearAvailableContext() {
+        context = null
+    }
+}
\ No newline at end of file
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java b/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java
deleted file mode 100644
index 99a299c..0000000
--- a/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020 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.activity.contextaware;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-
-/**
- * Listener for receiving a callback at the first moment a {@link Context} is made
- * available to the {@link ContextAware} class.
- *
- * @see ContextAware#addOnContextAvailableListener(OnContextAvailableListener)
- */
-public interface OnContextAvailableListener {
-
-    /**
-     * Called when the {@link ContextAware} object this listener was added to is associated to a
-     * {@link Context}.
-     *
-     * @param context The {@link Context} the {@link ContextAware} object is now associated with.
-     */
-    void onContextAvailable(@NonNull Context context);
-}
diff --git a/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.kt b/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.kt
new file mode 100644
index 0000000..e5e8f1f
--- /dev/null
+++ b/activity/activity/src/main/java/androidx/activity/contextaware/OnContextAvailableListener.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 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.activity.contextaware
+
+import android.content.Context
+
+/**
+ * Listener for receiving a callback at the first moment a [Context] is made
+ * available to the [ContextAware] class.
+ *
+ * @see ContextAware.addOnContextAvailableListener
+ */
+fun interface OnContextAvailableListener {
+    /**
+     * Called when the [ContextAware] object this listener was added to is associated to a
+     * [Context].
+     *
+     * @param context The [Context] the [ContextAware] object is now associated with.
+     */
+    fun onContextAvailable(context: Context)
+}
\ No newline at end of file
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.java
index c0c32f5..99e7d0b 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/ActionExecutor.java
@@ -18,6 +18,8 @@
 
 import androidx.annotation.NonNull;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
 /**
  * An interface of executing the action.
  *
@@ -29,39 +31,8 @@
      * Calls to execute the action.
      *
      * @param argument the argument for this action.
-     * @param callback the callback to send back the action execution result.
+     * @return A ListenableFuture containing the ExecutionResult
      */
-    void execute(@NonNull ArgumentT argument, @NonNull ActionCallback<OutputT> callback);
-
-    /** Reasons for the action execution error. */
-    enum ErrorStatus {
-        CANCELLED,
-        /** The action execution error was caused by a timeout. */
-        TIMEOUT,
-    }
-
-    /**
-     * An interface for receiving the result of action.
-     *
-     * @param <OutputT>
-     */
-    interface ActionCallback<OutputT> {
-
-        /** Invoke to set an action result upon success. */
-        void onSuccess(@NonNull ExecutionResult<OutputT> executionResult);
-
-        /** Invoke to set an action result upon success. */
-        default void onSuccess() {
-            onSuccess(ExecutionResult.<OutputT>newBuilderWithOutput().build());
-        }
-
-        /**
-         * Invokes to set an error status for the action.
-         *
-         * @deprecated
-         */
-        @Deprecated
-        void onError(@NonNull ErrorStatus errorStatus);
-    }
-
+    @NonNull
+    ListenableFuture<ExecutionResult<OutputT>> execute(@NonNull ArgumentT argument);
 }
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImpl.java b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImpl.java
index b4f281b..778b412 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImpl.java
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImpl.java
@@ -26,6 +26,8 @@
 import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper;
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal;
 import androidx.appactions.interaction.capabilities.core.impl.ErrorStatusInternal;
+import androidx.appactions.interaction.capabilities.core.impl.concurrent.FutureCallback;
+import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures;
 import androidx.appactions.interaction.capabilities.core.impl.exceptions.StructConversionException;
 import androidx.appactions.interaction.capabilities.core.impl.utils.CapabilityLogger;
 import androidx.appactions.interaction.capabilities.core.impl.utils.LoggerInternal;
@@ -97,7 +99,20 @@
                                                         .map(FulfillmentValue::getValue)
                                                         .collect(toImmutableList())));
         try {
-            mActionExecutor.execute(mActionSpec.buildArgument(args), convertCallback(callback));
+            Futures.addCallback(
+                    mActionExecutor.execute(mActionSpec.buildArgument(args)),
+                    new FutureCallback<ExecutionResult<OutputT>>() {
+                        @Override
+                        public void onSuccess(ExecutionResult<OutputT> executionResult) {
+                            callback.onSuccess(convertToFulfillmentResponse(executionResult));
+                        }
+
+                        @Override
+                        public void onFailure(Throwable t) {
+                            callback.onError(ErrorStatusInternal.CANCELLED);
+                        }
+                    },
+                    Runnable::run);
         } catch (StructConversionException e) {
             if (e.getMessage() != null) {
                 LoggerInternal.log(CapabilityLogger.LogLevel.ERROR, LOG_TAG, e.getMessage());
@@ -106,32 +121,11 @@
         }
     }
 
-    /** Converts {@link CallbackInternal} to {@link ActionExecutor.ActionCallback}. */
-    private ActionExecutor.ActionCallback<OutputT> convertCallback(CallbackInternal callback) {
-        return new ActionExecutor.ActionCallback<OutputT>() {
-            @Override
-            public void onSuccess(ExecutionResult<OutputT> executionResult) {
-                callback.onSuccess(convertToFulfillmentResponse(executionResult));
-            }
-
-            @Override
-            public void onError(ActionExecutor.ErrorStatus errorStatus) {
-                switch (errorStatus) {
-                    case CANCELLED:
-                        callback.onError(ErrorStatusInternal.CANCELLED);
-                        break;
-                    case TIMEOUT:
-                        callback.onError(ErrorStatusInternal.TIMEOUT);
-                }
-            }
-        };
-    }
-
     /** Converts typed {@link ExecutionResult} to {@link FulfillmentResponse} proto. */
     FulfillmentResponse convertToFulfillmentResponse(ExecutionResult<OutputT> executionResult) {
         FulfillmentResponse.Builder fulfillmentResponseBuilder =
-                FulfillmentResponse.newBuilder().setStartDictation(
-                        executionResult.getStartDictation());
+                FulfillmentResponse.newBuilder()
+                        .setStartDictation(executionResult.getStartDictation());
         OutputT output = executionResult.getOutput();
         if (output != null && !(output instanceof Void)) {
             fulfillmentResponseBuilder.setExecutionOutput(mActionSpec.convertOutputToProto(output));
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImplTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImplTest.java
index 4e2e5b8..47d20b5 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImplTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionCapabilityImplTest.java
@@ -23,6 +23,7 @@
 import androidx.appactions.interaction.capabilities.core.ExecutionResult;
 import androidx.appactions.interaction.capabilities.core.impl.ArgumentsWrapper;
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal;
+import androidx.appactions.interaction.capabilities.core.impl.concurrent.Futures;
 import androidx.appactions.interaction.capabilities.core.impl.converters.TypeConverters;
 import androidx.appactions.interaction.capabilities.core.properties.EntityProperty;
 import androidx.appactions.interaction.capabilities.core.testing.spec.Argument;
@@ -60,25 +61,25 @@
                             Property::requiredEntityField,
                             Argument.Builder::setRequiredEntityField)
                     .bindOptionalOutput(
-                            "optionalStringOutput", Output::optionalStringField,
+                            "optionalStringOutput",
+                            Output::optionalStringField,
                             TypeConverters::toParamValue)
                     .bindRepeatedOutput(
-                            "repeatedStringOutput", Output::repeatedStringField,
+                            "repeatedStringOutput",
+                            Output::repeatedStringField,
                             TypeConverters::toParamValue)
                     .build();
-    @Rule
-    public final MockitoRule mockito = MockitoJUnit.rule();
-    @Captor
-    ArgumentCaptor<FulfillmentResponse> mCaptor;
-    @Mock
-    private CallbackInternal mCallbackInternal;
+    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+    @Captor ArgumentCaptor<FulfillmentResponse> mCaptor;
+    @Mock private CallbackInternal mCallbackInternal;
 
     @Test
     @SuppressWarnings("JdkImmutableCollections")
     public void execute_convertExecutionResult() {
         Property property =
-                Property.newBuilder().setRequiredEntityField(
-                        EntityProperty.newBuilder().build()).build();
+                Property.newBuilder()
+                        .setRequiredEntityField(EntityProperty.newBuilder().build())
+                        .build();
 
         ExecutionResult<Output> executionResult =
                 ExecutionResult.<Output>newBuilderWithOutput()
@@ -93,27 +94,33 @@
                         ACTION_SPEC,
                         Optional.of("id"),
                         property,
-                        (argument, callback) -> callback.onSuccess(executionResult));
+                        (argument) -> Futures.immediateFuture(executionResult));
         StructuredOutput expectedExecutionOutput =
                 StructuredOutput.newBuilder()
                         .addOutputValues(
                                 OutputValue.newBuilder()
                                         .setName("optionalStringOutput")
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test2").build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test2")
+                                                        .build())
                                         .build())
                         .addOutputValues(
                                 OutputValue.newBuilder()
                                         .setName("repeatedStringOutput")
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test3").build())
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test4").build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test3")
+                                                        .build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test4")
+                                                        .build())
                                         .build())
                         .build();
 
-        capability.execute(ArgumentsWrapper.create(Fulfillment.getDefaultInstance()),
-                mCallbackInternal);
+        capability.execute(
+                ArgumentsWrapper.create(Fulfillment.getDefaultInstance()), mCallbackInternal);
 
         verify(mCallbackInternal).onSuccess(mCaptor.capture());
         assertThat(mCaptor.getValue().getExecutionOutput().getOutputValuesList())
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
index f2cc5b8..a2f6b6e 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/impl/spec/ActionSpecTest.java
@@ -28,6 +28,7 @@
 import androidx.appactions.interaction.capabilities.core.properties.EntityProperty;
 import androidx.appactions.interaction.capabilities.core.properties.EnumProperty;
 import androidx.appactions.interaction.capabilities.core.properties.StringProperty;
+import androidx.appactions.interaction.capabilities.core.testing.TestingUtils;
 import androidx.appactions.interaction.capabilities.core.testing.spec.Output;
 import androidx.appactions.interaction.capabilities.core.values.EntityValue;
 import androidx.appactions.interaction.proto.AppActionsContext.AppAction;
@@ -83,10 +84,12 @@
                             Property::repeatedStringField,
                             Argument.Builder::setRepeatedStringField)
                     .bindOptionalOutput(
-                            "optionalStringOutput", Output::optionalStringField,
+                            "optionalStringOutput",
+                            Output::optionalStringField,
                             TypeConverters::toParamValue)
                     .bindRepeatedOutput(
-                            "repeatedStringOutput", Output::repeatedStringField,
+                            "repeatedStringOutput",
+                            Output::repeatedStringField,
                             TypeConverters::toParamValue)
                     .build();
 
@@ -111,8 +114,8 @@
                         StringProperty.EMPTY);
 
         ActionCapabilityInternal capability =
-                (ActionCapabilityInternal) createCapability("id", property, (arg, callback) -> {
-                });
+                (ActionCapabilityInternal)
+                        createCapability("id", property, TestingUtils.createFakeActionExecutor());
 
         assertThat(capability.getAppAction())
                 .isEqualTo(
@@ -123,7 +126,8 @@
                                         IntentParameter.newBuilder()
                                                 .setName("requiredEntity")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("contact_2")
                                                                 .setName("Donald")
                                                                 .addAlternateNames("Duck")
@@ -163,11 +167,15 @@
                         Optional.of(
                                 EntityProperty.newBuilder()
                                         .addPossibleEntity(
-                                                Entity.newBuilder().setId("entity1").setName(
-                                                        "repeated entity1").build())
+                                                Entity.newBuilder()
+                                                        .setId("entity1")
+                                                        .setName("repeated entity1")
+                                                        .build())
                                         .addPossibleEntity(
-                                                Entity.newBuilder().setId("entity2").setName(
-                                                        "repeated entity2").build())
+                                                Entity.newBuilder()
+                                                        .setId("entity2")
+                                                        .setName("repeated entity2")
+                                                        .build())
                                         .setIsRequired(true)
                                         .build()),
                         StringProperty.EMPTY,
@@ -180,8 +188,8 @@
                         Optional.of(StringProperty.PROHIBITED));
 
         ActionCapabilityInternal capability =
-                (ActionCapabilityInternal) createCapability("id", property, (arg, callback) -> {
-                });
+                (ActionCapabilityInternal)
+                        createCapability("id", property, TestingUtils.createFakeActionExecutor());
 
         assertThat(capability.getAppAction())
                 .isEqualTo(
@@ -192,7 +200,8 @@
                                         IntentParameter.newBuilder()
                                                 .setName("requiredEntity")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("contact_2")
                                                                 .setName("Donald")
                                                                 .addAlternateNames("Duck")
@@ -203,7 +212,8 @@
                                         IntentParameter.newBuilder()
                                                 .setName("optionalEntity")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("entity1")
                                                                 .setName("optional possible entity")
                                                                 .build())
@@ -213,7 +223,8 @@
                                         IntentParameter.newBuilder()
                                                 .setName("optionalEnum")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier(
                                                                         TestEnum.VALUE_1.toString())
                                                                 .build())
@@ -223,12 +234,14 @@
                                         IntentParameter.newBuilder()
                                                 .setName("repeatedEntity")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("entity1")
                                                                 .setName("repeated entity1")
                                                                 .build())
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("entity2")
                                                                 .setName("repeated entity2")
                                                                 .build())
@@ -239,15 +252,17 @@
                                         IntentParameter.newBuilder()
                                                 .setName("optionalString")
                                                 .addPossibleEntities(
-                                                        androidx.appactions.interaction.proto.Entity.newBuilder()
+                                                        androidx.appactions.interaction.proto.Entity
+                                                                .newBuilder()
                                                                 .setIdentifier("value1")
                                                                 .setName("value1")
                                                                 .build())
                                                 .setIsRequired(true)
                                                 .setEntityMatchRequired(true))
                                 .addParams(
-                                        IntentParameter.newBuilder().setName(
-                                                "repeatedString").setIsProhibited(true))
+                                        IntentParameter.newBuilder()
+                                                .setName("repeatedString")
+                                                .setIsProhibited(true))
                                 .build());
     }
 
@@ -265,16 +280,22 @@
                         .addOutputValues(
                                 OutputValue.newBuilder()
                                         .setName("optionalStringOutput")
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test2").build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test2")
+                                                        .build())
                                         .build())
                         .addOutputValues(
                                 OutputValue.newBuilder()
                                         .setName("repeatedStringOutput")
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test3").build())
-                                        .addValues(ParamValue.newBuilder().setStringValue(
-                                                "test4").build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test3")
+                                                        .build())
+                                        .addValues(
+                                                ParamValue.newBuilder()
+                                                        .setStringValue("test4")
+                                                        .build())
                                         .build())
                         .build();
 
@@ -354,8 +375,8 @@
                     repeatedStringField);
         }
 
-        static Property create(EntityProperty requiredEntityField,
-                StringProperty requiredStringField) {
+        static Property create(
+                EntityProperty requiredEntityField, StringProperty requiredStringField) {
             return create(
                     requiredEntityField,
                     Optional.empty(),
diff --git a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/TestingUtils.java b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/TestingUtils.java
index da5a952..77a56b6 100644
--- a/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/TestingUtils.java
+++ b/appactions/interaction/interaction-capabilities-core/src/test/java/androidx/appactions/interaction/capabilities/core/testing/TestingUtils.java
@@ -17,6 +17,7 @@
 package androidx.appactions.interaction.capabilities.core.testing;
 
 import androidx.annotation.NonNull;
+import androidx.appactions.interaction.capabilities.core.ActionExecutor;
 import androidx.appactions.interaction.capabilities.core.ConfirmationOutput;
 import androidx.appactions.interaction.capabilities.core.ExecutionResult;
 import androidx.appactions.interaction.capabilities.core.impl.CallbackInternal;
@@ -200,4 +201,10 @@
             return mResultRef.get();
         }
     }
+
+    public static <ArgumentT, OutputT>
+            ActionExecutor<ArgumentT, OutputT> createFakeActionExecutor() {
+        return (args) ->
+                Futures.immediateFuture(ExecutionResult.<OutputT>getDefaultInstanceWithOutput());
+    }
 }
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
index 0d0853c..4739e54 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapter.kt
@@ -49,7 +49,7 @@
         for (useCase in useCases) {
             sessionConfigs.add(useCase.sessionConfig)
         }
-        getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        getSurfaceToStreamUseCaseMapping(sessionConfigs, shouldSetStreamUseCaseByDefault = false)
     }
     private val validatingBuilder: SessionConfig.ValidatingBuilder by lazy {
         val validatingBuilder = SessionConfig.ValidatingBuilder()
@@ -112,6 +112,7 @@
     @VisibleForTesting
     fun getSurfaceToStreamUseCaseMapping(
         sessionConfigs: Collection<SessionConfig>,
+        shouldSetStreamUseCaseByDefault: Boolean
     ): Map<DeferrableSurface, Long> {
         if (sessionConfigs.any { it.templateType == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG }) {
             // If is ZSL, do not populate anything.
@@ -138,8 +139,12 @@
                     continue
                 }
 
-                val streamUseCase = getStreamUseCaseForContainerClass(surface.containerClass)
-                mapping[surface] = streamUseCase
+                if (shouldSetStreamUseCaseByDefault) {
+                    // TODO(b/266879290) This is currently gated out because of camera device
+                    // crashing due to unsupported stream useCase combinations.
+                    val streamUseCase = getStreamUseCaseForContainerClass(surface.containerClass)
+                    mapping[surface] = streamUseCase
+                }
             }
         }
         return mapping
diff --git a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
index 0447f6a..362d5b9 100644
--- a/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
+++ b/camera/camera-camera2-pipe-integration/src/test/java/androidx/camera/camera2/pipe/integration/adapter/SessionConfigAdapterTest.kt
@@ -130,7 +130,7 @@
 
     @Test
     fun populateSurfaceToStreamUseCaseMappingEmptyUseCase() {
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(listOf())
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(listOf(), true)
         TestCase.assertTrue(mapping.isEmpty())
     }
 
@@ -141,7 +141,7 @@
         Mockito.`when`(mockSessionConfig.implementationOptions).thenReturn(mockImplementationOption)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping[mockSurface] == 0L)
     }
 
@@ -152,7 +152,7 @@
         Mockito.`when`(mockSessionConfig.implementationOptions).thenReturn(mockImplementationOption)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isNotEmpty())
         TestCase.assertTrue(mapping[mockSurface] == 1L)
     }
@@ -167,7 +167,7 @@
             .thenReturn(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isEmpty())
     }
 
@@ -179,7 +179,7 @@
             .thenReturn(mockImplementationOption)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isNotEmpty())
         TestCase.assertTrue(mapping[mockSurface] == 1L)
     }
@@ -191,7 +191,7 @@
         Mockito.`when`(mockSessionConfig.implementationOptions).thenReturn(mockImplementationOption)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isNotEmpty())
         TestCase.assertTrue(mapping[mockSurface] == 2L)
     }
@@ -203,7 +203,7 @@
         Mockito.`when`(mockSessionConfig.implementationOptions).thenReturn(mockImplementationOption)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isNotEmpty())
         TestCase.assertTrue(mapping[mockSurface] == 3L)
     }
@@ -220,7 +220,7 @@
             .thenReturn(0L)
         val sessionConfigs: MutableCollection<SessionConfig> = ArrayList()
         sessionConfigs.add(mockSessionConfig)
-        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs)
+        val mapping = sessionConfigAdapter.getSurfaceToStreamUseCaseMapping(sessionConfigs, true)
         TestCase.assertTrue(mapping.isNotEmpty())
         TestCase.assertTrue(mapping[mockSurface] == 0L)
     }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index d14efa6..27723ed 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -1134,7 +1134,7 @@
         Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
                 mUseCaseAttachState.getAttachedSessionConfigs(),
-                streamUseCaseMap, mCameraCharacteristicsCompat);
+                streamUseCaseMap, mCameraCharacteristicsCompat, false);
 
         mCaptureSession.setStreamUseCaseMap(streamUseCaseMap);
 
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
index f2c6f0e..d2e5dd8 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
@@ -65,7 +65,8 @@
     public static void populateSurfaceToStreamUseCaseMapping(
             @NonNull Collection<SessionConfig> sessionConfigs,
             @NonNull Map<DeferrableSurface, Long> streamUseCaseMap,
-            @NonNull CameraCharacteristicsCompat cameraCharacteristicsCompat) {
+            @NonNull CameraCharacteristicsCompat cameraCharacteristicsCompat,
+            boolean shouldSetStreamUseCaseByDefault) {
         if (Build.VERSION.SDK_INT < 33) {
             return;
         }
@@ -100,12 +101,16 @@
                     continue;
                 }
 
-                Long streamUseCase = getUseCaseToStreamUseCaseMapping()
-                        .get(surface.getContainerClass());
-                putStreamUseCaseToMappingIfAvailable(streamUseCaseMap,
-                        surface,
-                        streamUseCase,
-                        supportedStreamUseCases);
+                if (shouldSetStreamUseCaseByDefault) {
+                    // TODO(b/266879290) This is currently gated out because of camera device
+                    // crashing due to unsupported stream useCase combinations.
+                    Long streamUseCase = getUseCaseToStreamUseCaseMapping()
+                            .get(surface.getContainerClass());
+                    putStreamUseCaseToMappingIfAvailable(streamUseCaseMap,
+                            surface,
+                            streamUseCase,
+                            supportedStreamUseCases);
+                }
             }
         }
     }
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
index f245ae2..c8888da 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/StreamUseCaseTest.java
@@ -88,7 +88,7 @@
         Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
         mMockSurface.setContainerClass(Preview.class);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat());
+                new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -97,7 +97,7 @@
     public void getStreamUseCaseFromUseCaseEmptyUseCase() {
         Map<DeferrableSurface, Long> streamUseCaseMap = new HashMap<>();
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat());
+                new ArrayList<>(), streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -112,7 +112,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -126,7 +126,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface)
                 == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
     }
@@ -144,7 +144,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -159,7 +159,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface)
                 == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
     }
@@ -175,7 +175,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface)
                 == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE);
     }
@@ -191,7 +191,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface)
                 == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD);
     }
@@ -208,7 +208,8 @@
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
                 sessionConfigs, streamUseCaseMap,
-                CameraCharacteristicsCompat.toCameraCharacteristicsCompat(mCameraCharacteristics));
+                CameraCharacteristicsCompat.toCameraCharacteristicsCompat(mCameraCharacteristics),
+                true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -225,7 +226,8 @@
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
                 sessionConfigs,
                 streamUseCaseMap,
-                getCameraCharacteristicsCompatWithEmptyUseCases());
+                getCameraCharacteristicsCompatWithEmptyUseCases(),
+                true);
         assertTrue(streamUseCaseMap.isEmpty());
     }
 
@@ -242,7 +244,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface) == 3L);
     }
 
@@ -259,7 +261,7 @@
         ArrayList<SessionConfig> sessionConfigs = new ArrayList<>();
         sessionConfigs.add(sessionConfig);
         StreamUseCaseUtil.populateSurfaceToStreamUseCaseMapping(
-                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat());
+                sessionConfigs, streamUseCaseMap, getCameraCharacteristicsCompat(), true);
         assertTrue(streamUseCaseMap.get(mMockSurface)
                 == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW);
     }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index 45d12bd..ad3c388 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -300,6 +300,7 @@
             // Attach new UseCases.
             for (UseCase useCase : cameraUseCasesToAttach) {
                 ConfigPair configPair = requireNonNull(configs.get(useCase));
+                useCase.setHasCameraTransform(true);
                 useCase.bindToCamera(mCameraInternal, configPair.mExtendedConfig,
                         configPair.mCameraConfig);
                 useCase.updateSuggestedStreamSpec(
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
index 1a5ec39..fa70b29 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/streamsharing/VirtualCamera.java
@@ -96,6 +96,7 @@
 
     void bindChildren() {
         for (UseCase useCase : mChildren) {
+            useCase.setHasCameraTransform(false);
             useCase.bindToCamera(this, null,
                     useCase.getDefaultConfig(true, mUseCaseConfigFactory));
         }
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 d1dae4c..122860b 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
@@ -645,7 +645,7 @@
         previewToDetach = Preview.Builder()
             .setTargetRotation(Surface.ROTATION_0)
             .build()
-        previewToDetach.setHasCameraTransform(hasCameraTransform)
+        previewToDetach.hasCameraTransform = hasCameraTransform
         previewToDetach.processor = surfaceProcessor
         previewToDetach.setSurfaceProvider(CameraXExecutors.directExecutor()) {}
         val previewConfig = PreviewConfig(
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
index 6680e50..2f6869c3 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.kt
@@ -141,6 +141,11 @@
         // Assert: StreamSharing children are bound
         assertThat(preview.camera).isNotNull()
         assertThat(video.camera).isNotNull()
+        // Assert: has camera transform bit.
+        assertThat(preview.hasCameraTransform).isFalse()
+        assertThat(video.hasCameraTransform).isFalse()
+        assertThat(image.hasCameraTransform).isTrue()
+        assertThat(adapter.getStreamSharing().hasCameraTransform).isTrue()
     }
 
     @Test
@@ -154,6 +159,8 @@
             Preview::class.java,
             FakeUseCase::class.java
         )
+        assertThat(preview.hasCameraTransform).isTrue()
+        assertThat(video.hasCameraTransform).isTrue()
     }
 
     @Test(expected = CameraException::class)
@@ -176,6 +183,8 @@
             FakeUseCase::class.java,
             ImageCapture::class.java
         )
+        assertThat(image.hasCameraTransform).isTrue()
+        assertThat(video.hasCameraTransform).isTrue()
         // Act: add a new UseCase that needs StreamSharing
         adapter.addUseCases(setOf(preview))
         // Assert: StreamSharing is created.
@@ -187,6 +196,11 @@
         assertThat(preview.camera).isNotNull()
         assertThat(video.camera).isNotNull()
         assertThat(image.camera).isNotNull()
+        // Assert: hasCameraTransform bit
+        assertThat(preview.hasCameraTransform).isFalse()
+        assertThat(video.hasCameraTransform).isFalse()
+        assertThat(image.hasCameraTransform).isTrue()
+        assertThat(adapter.getStreamSharing().hasCameraTransform).isTrue()
     }
 
     @Test
@@ -203,6 +217,11 @@
         val streamSharing =
             adapter.cameraUseCases.filterIsInstance(StreamSharing::class.java).single()
         assertThat(streamSharing.camera).isNotNull()
+        // Assert: hasCameraTransform bit
+        assertThat(preview.hasCameraTransform).isFalse()
+        assertThat(video.hasCameraTransform).isFalse()
+        assertThat(image.hasCameraTransform).isTrue()
+        assertThat(adapter.getStreamSharing().hasCameraTransform).isTrue()
         // Act: remove UseCase so that StreamSharing is no longer needed
         adapter.removeUseCases(setOf(video))
         // Assert: StreamSharing removed and unbound.
@@ -211,6 +230,9 @@
             ImageCapture::class.java
         )
         assertThat(streamSharing.camera).isNull()
+        // Assert: hasCameraTransform bit
+        assertThat(image.hasCameraTransform).isTrue()
+        assertThat(preview.hasCameraTransform).isTrue()
     }
 
     @Test(expected = CameraException::class)
@@ -229,7 +251,7 @@
         // Act: add UseCases that require StreamSharing
         adapter.addUseCases(setOf(preview, video, image))
         // Assert: StreamSharing is used.
-        val streamSharing = adapter.cameraUseCases.filterIsInstance<StreamSharing>().single()
+        val streamSharing = adapter.getStreamSharing()
         adapter.cameraUseCases.hasExactTypes(
             StreamSharing::class.java,
             ImageCapture::class.java
@@ -237,9 +259,7 @@
         // Act: add another UseCase
         adapter.addUseCases(setOf(analysis))
         // Assert: the same StreamSharing instance is kept.
-        assertThat(
-            adapter.cameraUseCases.filterIsInstance<StreamSharing>().single()
-        ).isSameInstanceAs(streamSharing)
+        assertThat(adapter.getStreamSharing()).isSameInstanceAs(streamSharing)
         adapter.cameraUseCases.hasExactTypes(
             StreamSharing::class.java,
             ImageCapture::class.java,
@@ -247,6 +267,10 @@
         )
     }
 
+    private fun CameraUseCaseAdapter.getStreamSharing(): StreamSharing {
+        return this.cameraUseCases.filterIsInstance(StreamSharing::class.java).single()
+    }
+
     private fun createFakeVideoCapture(): FakeUseCase {
         val fakeUseCaseConfig = FakeUseCaseConfig.Builder()
             .setBufferFormat(ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
index 945dd35..dd46cef 100644
--- a/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
+++ b/camera/camera-video/src/test/java/androidx/camera/video/VideoCaptureTest.kt
@@ -145,14 +145,17 @@
     fun setNoCameraTransform_propagatesToCameraEdge() {
         // Arrange.
         setupCamera()
-        createCameraUseCaseAdapter()
         val processor = createFakeSurfaceProcessor()
         val videoCapture = createVideoCapture(createVideoOutput(), processor = processor)
-        // Act.
-        videoCapture.setHasCameraTransform(false)
-        addAndAttachUseCases(videoCapture)
-        // Assert.
+        // Act: set no transform and create pipeline.
+        videoCapture.hasCameraTransform = false
+        videoCapture.bindToCamera(camera, null, null)
+        videoCapture.updateSuggestedStreamSpec(StreamSpec.builder(Size(640, 480)).build())
+        videoCapture.onStateAttached()
+        // Assert: camera edge does not have transform.
         assertThat(videoCapture.cameraEdge!!.hasCameraTransform()).isFalse()
+        videoCapture.onStateDetached()
+        videoCapture.unbindFromCamera(camera)
     }
 
     @Test
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt
index a1d1b2f..c4a8f61 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ClickableTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.foundation
 
-import android.os.Build
+import android.os.Build.VERSION.SDK_INT
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.foundation.gestures.draggable
@@ -44,11 +44,15 @@
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
+import androidx.compose.ui.input.InputModeManager
 import androidx.compose.ui.input.key.Key
 import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsActions
@@ -79,7 +83,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
@@ -106,7 +109,12 @@
     @After
     fun after() {
         isDebugInspectorInfoEnabled = false
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
+    }
+
+    // TODO(b/267253920): Add a compose test API to set/reset InputMode.
+    @After
+    fun resetTouchMode() = with(InstrumentationRegistry.getInstrumentation()) {
+        if (SDK_INT < 33) setInTouchMode(true) else resetInTouchMode()
     }
 
     @Test
@@ -208,16 +216,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_clickWithEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                     "ClickableText",
                     modifier = Modifier
@@ -226,8 +230,10 @@
                         .clickable { counter++ }
             )
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("myClickable").performKeyInput { keyDown(Key.Enter) }
 
@@ -240,16 +246,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_clickWithNumPadEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ClickableText",
                 modifier = Modifier
@@ -258,8 +260,10 @@
                     .clickable { counter++ }
             )
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("myClickable").performKeyInput { keyDown(Key.NumPadEnter) }
 
@@ -272,16 +276,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_clickWithDPadCenter() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ClickableText",
                 modifier = Modifier
@@ -290,8 +290,10 @@
                     .clickable { counter++ }
             )
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("myClickable").performKeyInput { keyDown(Key.DirectionCenter) }
 
@@ -1246,13 +1248,13 @@
 
     @Test
     fun clickableTest_interactionSource_focus_inTouchMode() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
-
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box {
                 BasicText(
                     "ClickableText",
@@ -1266,6 +1268,10 @@
                 )
             }
         }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Touch)
+        }
 
         val interactions = mutableListOf<Interaction>()
 
@@ -1288,21 +1294,16 @@
     }
 
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_interactionSource_focus_inKeyboardMode() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
         lateinit var focusManager: FocusManager
-
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
             focusManager = LocalFocusManager.current
+            inputModeManager = LocalInputModeManager.current
                 Box {
                     BasicText(
                         "ClickableText",
@@ -1316,6 +1317,10 @@
                     )
                 }
         }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+        }
 
         val interactions = mutableListOf<Interaction>()
 
@@ -1941,18 +1946,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_enterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -1965,8 +1966,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1991,18 +1994,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_numPadEnterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2015,8 +2014,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -2041,18 +2042,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_dpadCenter_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2065,8 +2062,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
         rule.waitForIdle()
 
         val interactions = mutableListOf<Interaction>()
@@ -2093,12 +2092,13 @@
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
     fun clickableTest_otherKey_doesNotEmitIndication() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2111,8 +2111,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -2127,18 +2129,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_doubleEnterKey_emitsFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2151,8 +2149,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -2191,19 +2191,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_repeatKeyEvents_doNotEmitFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         var repeatCounter = 0
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2221,8 +2217,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -2254,20 +2252,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun clickableTest_interruptedClick_emitsCancelIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         val enabled = mutableStateOf(true)
         lateinit var scope: CoroutineScope
-
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ClickableText",
                     modifier = Modifier
@@ -2281,8 +2274,10 @@
                 )
             }
         }
-
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
index 5319fdd..f852d45 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ImageTest.kt
@@ -66,7 +66,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
-import androidx.test.filters.RequiresDevice
 import androidx.test.filters.SdkSuppress
 import org.junit.Assert
 import org.junit.Assert.assertEquals
@@ -81,8 +80,8 @@
 
     val contentTag = "ImageTest"
 
-    val imageWidth = 100
-    val imageHeight = 100
+    val imageWidth = 300
+    val imageHeight = 300
     val containerSize = imageWidth
 
     val bgColor = Color.Blue
@@ -254,7 +253,6 @@
         }
     }
 
-    @RequiresDevice // b/264704089
     @Test
     fun testImageFixedSizeIsStretched() {
         val imageComposableWidth = imageWidth * 2
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollAccessibilityTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
index 2293c1a..3371446 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
@@ -32,7 +32,6 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
@@ -41,15 +40,15 @@
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
 import androidx.core.view.ViewCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import com.google.common.truth.IterableSubject
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -100,6 +99,22 @@
                 .provider as AccessibilityNodeProvider
         }
 
+    private val itemSize = 21
+    private var itemSizeDp: Dp = Dp.Unspecified
+    private val containerSize = 200
+    private var containerSizeDp: Dp = Dp.Unspecified
+    private val contentPadding = 50
+    private var contentPaddingDp: Dp = Dp.Unspecified
+
+    @Before
+    fun before() {
+        with(rule.density) {
+            itemSizeDp = itemSize.toDp()
+            containerSizeDp = containerSize.toDp()
+            contentPaddingDp = contentPadding.toDp()
+        }
+    }
+
     @Test
     fun scrollForward() {
         testRelativeDirection(58, ACTION_SCROLL_FORWARD)
@@ -148,7 +163,6 @@
         )
     }
 
-    @SdkSuppress(minSdkVersion = 29) // b/260010883
     @Test
     fun verifyScrollActionsAtEnd() {
         createScrollableContent_StartAtEnd()
@@ -277,13 +291,13 @@
     private fun createScrollableContent_StartInMiddle() {
         createScrollableContent {
             // Start at the middle:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> centered when 1000dp on either side, which is 47 items + 13dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> centered when 1000 on either side, which is 47 items + 13
             rememberLazyGridState(
                 47,
-                with(LocalDensity.current) { 13.dp.roundToPx() }
+                13
             )
         }
     }
@@ -294,19 +308,19 @@
     private fun createScrollableContent_StartAtEnd() {
         createScrollableContent {
             // Start at the end:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> at the end when offset at 2000dp, which is 95 items + 5dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> at the end when offset at 2000, which is 95 items + 5
             rememberLazyGridState(
                 95,
-                with(LocalDensity.current) { 5.dp.roundToPx() }
+                5
             )
         }
     }
 
     /**
-     * Creates a grid with a viewport of 100.dp, containing 100 items each 17.dp in size.
+     * Creates a grid with a viewport of 100 px, containing 100 items each 21 px in size.
      * The items have a text with their index (ASC), and where the viewport starts is determined
      * by the given [lambda][rememberLazyGridState]. All properties from [config] are applied.
      * The viewport has padding around it to make sure scroll distance doesn't include padding.
@@ -317,18 +331,18 @@
 
             val state = rememberLazyGridState()
 
-            Box(Modifier.requiredSize(200.dp).background(Color.White)) {
+            Box(Modifier.requiredSize(containerSizeDp).background(Color.White)) {
                 val direction = if (config.rtl) LayoutDirection.Rtl else LayoutDirection.Ltr
                 CompositionLocalProvider(LocalLayoutDirection provides direction) {
                     LazyGrid(
                         cells = 1,
                         modifier = Modifier.testTag(scrollerTag).matchParentSize(),
                         state = state,
-                        contentPadding = PaddingValues(50.dp),
+                        contentPadding = PaddingValues(contentPaddingDp),
                         reverseLayout = config.reversed
                     ) {
                         items(100) {
-                            Box(Modifier.requiredSize(21.dp).background(Color.Yellow)) {
+                            Box(Modifier.requiredSize(itemSizeDp).background(Color.Yellow)) {
                                 BasicText("$it", Modifier.align(Alignment.Center))
                             }
                         }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
index b24abb5..e8dcc77 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
@@ -34,7 +34,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,7 +53,7 @@
         var counter2 = 100
         var realState = arrayOf(0, 0, 0)
         restorationTester.setContent {
-            LazyLayout(3) {
+            LazyLayout({ 3 }) {
                 if (it == 0) {
                     realState[0] = rememberSaveable { counter0++ }
                 } else if (it == 1) {
@@ -90,7 +89,7 @@
         var realState = 0
         rule.setContent {
             LazyLayout(
-                itemCount = 2,
+                itemCount = { 2 },
                 itemIsVisible = { it == visibleItem }
             ) {
                 if (it == 0) {
@@ -129,11 +128,11 @@
         var realState = 0
         rule.setContent {
             LazyLayout(
-                itemCount = 2,
+                itemCount = { 2 },
                 itemIsVisible = { it == visibleItem }
             ) {
                 if (it == 0) {
-                    LazyLayout(itemCount = 1) {
+                    LazyLayout(itemCount = { 1 }) {
                         realState = rememberSaveable { counter0++ }
                         DisposableEffect(Unit) {
                             onDispose {
@@ -173,7 +172,7 @@
         var realState = arrayOf(0, 0, 0)
         restorationTester.setContent {
             LazyLayout(
-                itemCount = 3,
+                itemCount = { 3 },
                 indexToKey = { "$it" }
             ) {
                 if (it == 0) {
@@ -203,7 +202,6 @@
         }
     }
 
-    @Ignore // b/260866527
     @Test
     fun stateRestoredWhenUsedWithCustomKeysAfterReordering() {
         val restorationTester = StateRestorationTester(rule)
@@ -214,8 +212,8 @@
         var list by mutableStateOf(listOf(0, 1, 2))
         restorationTester.setContent {
             LazyLayout(
-                itemCount = list.size,
-                indexToKey = { "${list.getOrNull(it)}" }
+                itemCount = { list.size },
+                indexToKey = { "${list[it]}" }
             ) { index ->
                 val it = list[index]
                 if (it == 0) {
@@ -230,7 +228,7 @@
         }
 
         rule.runOnIdle {
-            list = listOf(1, 2)
+            list = listOf(1, 2, 0)
         }
 
         rule.runOnIdle {
@@ -243,7 +241,7 @@
         restorationTester.emulateSavedInstanceStateRestore()
 
         rule.runOnIdle {
-            Truth.assertThat(realState[0]).isEqualTo(0)
+            Truth.assertThat(realState[0]).isEqualTo(1)
             Truth.assertThat(realState[1]).isEqualTo(10)
             Truth.assertThat(realState[2]).isEqualTo(100)
         }
@@ -259,7 +257,7 @@
         }
         restorationTester.setContent {
             LazyLayout(
-                itemCount = 100,
+                itemCount = { 100 },
                 itemIsVisible = { visibleRange.contains(it) }
             ) {
                 realState[it] = rememberSaveable { stateToUse }
@@ -296,15 +294,15 @@
     @OptIn(ExperimentalFoundationApi::class)
     @Composable
     private fun LazyLayout(
-        itemCount: Int,
+        itemCount: () -> Int,
         itemIsVisible: (Int) -> Boolean = { true },
         indexToKey: (Int) -> Any = { getDefaultLazyLayoutKey(it) },
         content: @Composable (Int) -> Unit
     ) {
         LazyLayout(
-            itemProvider = remember(itemCount, content as Any) {
+            itemProvider = remember(itemCount, indexToKey, content as Any) {
                 object : LazyLayoutItemProvider {
-                    override val itemCount: Int = itemCount
+                    override val itemCount: Int = itemCount()
 
                     @Composable
                     override fun Item(index: Int) {
@@ -316,7 +314,7 @@
             }
         ) { constraints ->
             val placeables = mutableListOf<Placeable>()
-            repeat(itemCount) { index ->
+            repeat(itemCount()) { index ->
                 if (itemIsVisible(index)) {
                     placeables.addAll(measure(index, constraints))
                 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyScrollAccessibilityTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyScrollAccessibilityTest.kt
index a29edf6..15fd4f6 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyScrollAccessibilityTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyScrollAccessibilityTest.kt
@@ -38,7 +38,6 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
@@ -48,15 +47,15 @@
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
 import androidx.core.view.ViewCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import com.google.common.truth.IterableSubject
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -107,6 +106,22 @@
                 .provider as AccessibilityNodeProvider
         }
 
+    private val itemSize = 21
+    private var itemSizeDp: Dp = Dp.Unspecified
+    private val containerSize = 200
+    private var containerSizeDp: Dp = Dp.Unspecified
+    private val contentPadding = 50
+    private var contentPaddingDp: Dp = Dp.Unspecified
+
+    @Before
+    fun before() {
+        with(rule.density) {
+            itemSizeDp = itemSize.toDp()
+            containerSizeDp = containerSize.toDp()
+            contentPaddingDp = contentPadding.toDp()
+        }
+    }
+
     @Test
     fun scrollForward() {
         testRelativeDirection(58, ACTION_SCROLL_FORWARD)
@@ -155,7 +170,6 @@
         )
     }
 
-    @SdkSuppress(minSdkVersion = 29) // b/260011449
     @Test
     fun verifyScrollActionsAtEnd() {
         createScrollableContent_StartAtEnd()
@@ -284,13 +298,13 @@
     private fun createScrollableContent_StartInMiddle() {
         createScrollableContent {
             // Start at the middle:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> centered when 1000dp on either side, which is 47 items + 13dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> centered when 1000 on either side, which is 47 items + 13
             rememberLazyListState(
                 47,
-                with(LocalDensity.current) { 13.dp.roundToPx() }
+                13
             )
         }
     }
@@ -301,19 +315,19 @@
     private fun createScrollableContent_StartAtEnd() {
         createScrollableContent {
             // Start at the end:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> at the end when offset at 2000dp, which is 95 items + 5dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> at the end when offset at 2000, which is 95 items + 5
             rememberLazyListState(
                 95,
-                with(LocalDensity.current) { 5.dp.roundToPx() }
+                5
             )
         }
     }
 
     /**
-     * Creates a Row/Column with a viewport of 100.dp, containing 100 items each 17.dp in size.
+     * Creates a Row/Column with a viewport of 100 px, containing 100 items each 21 px in size.
      * The items have a text with their index (ASC), and where the viewport starts is determined
      * by the given [lambda][rememberLazyListState]. All properties from [config] are applied.
      * The viewport has padding around it to make sure scroll distance doesn't include padding.
@@ -323,7 +337,7 @@
             composeView = LocalView.current
             val lazyContent: LazyListScope.() -> Unit = {
                 items(100) {
-                    Box(Modifier.requiredSize(21.dp).background(Color.Yellow)) {
+                    Box(Modifier.requiredSize(itemSizeDp).background(Color.Yellow)) {
                         BasicText("$it", Modifier.align(Alignment.Center))
                     }
                 }
@@ -331,14 +345,14 @@
 
             val state = rememberLazyListState()
 
-            Box(Modifier.requiredSize(200.dp).background(Color.White)) {
+            Box(Modifier.requiredSize(containerSizeDp).background(Color.White)) {
                 val direction = if (config.rtl) LayoutDirection.Rtl else LayoutDirection.Ltr
                 CompositionLocalProvider(LocalLayoutDirection provides direction) {
                     if (config.horizontal) {
                         LazyRow(
                             Modifier.testTag(scrollerTag).matchParentSize(),
                             state = state,
-                            contentPadding = PaddingValues(50.dp),
+                            contentPadding = PaddingValues(contentPaddingDp),
                             reverseLayout = config.reversed,
                             verticalAlignment = Alignment.CenterVertically
                         ) {
@@ -348,7 +362,7 @@
                         LazyColumn(
                             Modifier.testTag(scrollerTag).matchParentSize(),
                             state = state,
-                            contentPadding = PaddingValues(50.dp),
+                            contentPadding = PaddingValues(contentPaddingDp),
                             reverseLayout = config.reversed,
                             horizontalAlignment = Alignment.CenterHorizontally
                         ) {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
index a4a49a9..5b384af 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/SelectableTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.foundation.selection
 
-import android.os.Build
+import android.os.Build.VERSION.SDK_INT
 import androidx.compose.foundation.TapIndicationDelay
 import androidx.compose.foundation.interaction.FocusInteraction
 import androidx.compose.foundation.interaction.HoverInteraction
@@ -40,10 +40,14 @@
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
+import androidx.compose.ui.input.InputModeManager
 import androidx.compose.ui.input.key.Key
 import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsProperties
@@ -67,7 +71,6 @@
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
@@ -93,7 +96,12 @@
     @After
     fun after() {
         isDebugInspectorInfoEnabled = false
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
+    }
+
+    // TODO(b/267253920): Add a compose test API to set/reset InputMode.
+    @After
+    fun resetTouchMode() = with(InstrumentationRegistry.getInstrumentation()) {
+        if (SDK_INT < 33) setInTouchMode(true) else resetInTouchMode()
     }
 
     @Test
@@ -486,13 +494,14 @@
 
     @Test
     fun selectableTest_interactionSource_focus_inTouchMode() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box {
                 Box(
                     Modifier
@@ -520,6 +529,8 @@
         }
 
         rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Touch)
             focusRequester.requestFocus()
         }
 
@@ -530,21 +541,17 @@
     }
 
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_interactionSource_focus_inKeyboardMode() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
         lateinit var focusManager: FocusManager
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
             focusManager = LocalFocusManager.current
+            inputModeManager = LocalInputModeManager.current
                 Box {
                     Box(
                         Modifier
@@ -572,6 +579,8 @@
         }
 
         rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
             focusRequester.requestFocus()
         }
 
@@ -636,16 +645,13 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_clickWithEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "SelectableText",
                 modifier = Modifier
@@ -655,7 +661,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("selectable").performKeyInput { keyDown(Key.Enter) }
 
@@ -668,16 +678,13 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_clickWithNumPadEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "SelectableText",
                 modifier = Modifier
@@ -687,7 +694,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("selectable").performKeyInput { keyDown(Key.NumPadEnter) }
 
@@ -700,16 +711,13 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_clickWithDPadCenter() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         var counter = 0
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "SelectableText",
                 modifier = Modifier
@@ -719,7 +727,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         rule.onNodeWithTag("selectable").performKeyInput { keyDown(Key.DirectionCenter) }
 
@@ -732,18 +744,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_enterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -758,7 +767,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -783,18 +796,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_numPadEnterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -809,7 +819,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -834,18 +848,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_dpadCenter_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -860,7 +871,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
         rule.waitForIdle()
 
         val interactions = mutableListOf<Interaction>()
@@ -887,12 +902,14 @@
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
     fun selectableTest_otherKey_doesNotEmitIndication() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -907,7 +924,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -922,18 +943,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_doubleEnterKey_emitsFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -948,7 +966,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -987,19 +1009,16 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_repeatKeyEvents_doNotEmitFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         var repeatCounter = 0
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -1019,7 +1038,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1053,20 +1076,16 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun selectableTest_interruptedClick_emitsCancelIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         val enabled = mutableStateOf(true)
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("SelectableText",
                     modifier = Modifier
@@ -1082,7 +1101,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
index f48a9ee..4174820 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/selection/ToggleableTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.foundation.selection
 
-import android.os.Build
+import android.os.Build.VERSION.SDK_INT
 import androidx.compose.foundation.TapIndicationDelay
 import androidx.compose.foundation.interaction.FocusInteraction
 import androidx.compose.foundation.interaction.HoverInteraction
@@ -43,10 +43,14 @@
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
+import androidx.compose.ui.input.InputModeManager
 import androidx.compose.ui.input.key.Key
 import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.LocalInputModeManager
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsProperties
@@ -76,7 +80,6 @@
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
@@ -102,7 +105,12 @@
     @After
     fun after() {
         isDebugInspectorInfoEnabled = false
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
+    }
+
+    // TODO(b/267253920): Add a compose test API to set/reset InputMode.
+    @After
+    fun resetTouchMode() = with(InstrumentationRegistry.getInstrumentation()) {
+        if (SDK_INT < 33) setInTouchMode(true) else resetInTouchMode()
     }
 
     @Test
@@ -578,13 +586,14 @@
 
     @Test
     fun toggleableTest_interactionSource_focus_inTouchMode() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(true)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box {
                 Box(
                     Modifier
@@ -612,6 +621,8 @@
         }
 
         rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Touch)
             focusRequester.requestFocus()
         }
 
@@ -622,21 +633,17 @@
     }
 
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_interactionSource_focus_inKeyboardMode() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         lateinit var scope: CoroutineScope
         val focusRequester = FocusRequester()
         lateinit var focusManager: FocusManager
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
             focusManager = LocalFocusManager.current
+            inputModeManager = LocalInputModeManager.current
             Box {
                     Box(
                         Modifier
@@ -664,6 +671,8 @@
         }
 
         rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
             focusRequester.requestFocus()
         }
 
@@ -827,16 +836,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_clickWithEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
         var toggled by mutableStateOf(false)
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ToggleableText",
                 modifier = Modifier
@@ -846,7 +851,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val toggleableNode = rule.onNodeWithTag("toggleable")
         rule.runOnIdle { assertThat(toggled).isFalse() }
@@ -860,16 +869,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_clickWithNumPadEnterKey() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val focusRequester = FocusRequester()
         var toggled by mutableStateOf(false)
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ToggleableText",
                 modifier = Modifier
@@ -879,7 +884,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val toggleableNode = rule.onNodeWithTag("toggleable")
         rule.runOnIdle { assertThat(toggled).isFalse() }
@@ -893,16 +902,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_clickWithDpadCenter() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val focusRequester = FocusRequester()
         var toggled by mutableStateOf(false)
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ToggleableText",
                 modifier = Modifier
@@ -912,7 +917,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val toggleableNode = rule.onNodeWithTag("toggleable")
         rule.runOnIdle { assertThat(toggled).isFalse() }
@@ -926,16 +935,12 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class, ExperimentalComposeUiApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_clickWithEnterKey_triStateToggleable() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val focusRequester = FocusRequester()
         var toggled by mutableStateOf(false)
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             BasicText(
                 "ToggleableText",
                 modifier = Modifier
@@ -945,7 +950,11 @@
             )
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val toggleableNode = rule.onNodeWithTag("toggleable")
         rule.runOnIdle { assertThat(toggled).isFalse() }
@@ -959,17 +968,13 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_enterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
+            inputModeManager = LocalInputModeManager.current
             scope = rememberCoroutineScope()
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
@@ -985,7 +990,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1010,18 +1019,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_numPadEnterKey_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
+
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1036,7 +1042,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1061,18 +1071,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_dpadCenter_emitsIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1087,7 +1093,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
         rule.waitForIdle()
 
         val interactions = mutableListOf<Interaction>()
@@ -1114,12 +1124,13 @@
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
     fun toggleableTest_otherKey_doesNotEmitIndication() {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
+        lateinit var inputModeManager: InputModeManager
         lateinit var scope: CoroutineScope
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1134,7 +1145,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1149,18 +1164,14 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_doubleEnterKey_emitsFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1175,7 +1186,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1214,19 +1229,15 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_repeatKeyEvents_doNotEmitFurtherInteractions() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
         var repeatCounter = 0
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1246,7 +1257,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
@@ -1278,20 +1293,16 @@
 
     @Test
     @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun toggleableTest_interruptedClick_emitsCancelIndication() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(false)
         val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         val enabled = mutableStateOf(true)
         lateinit var scope: CoroutineScope
+        lateinit var inputModeManager: InputModeManager
 
         rule.setContent {
             scope = rememberCoroutineScope()
+            inputModeManager = LocalInputModeManager.current
             Box(Modifier.padding(10.dp)) {
                 BasicText("ToggleableText",
                     modifier = Modifier
@@ -1307,7 +1318,11 @@
             }
         }
 
-        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle {
+            @OptIn(ExperimentalComposeUiApi::class)
+            inputModeManager.requestInputMode(Keyboard)
+            focusRequester.requestFocus()
+        }
 
         val interactions = mutableListOf<Interaction>()
         scope.launch {
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ElevationOverlayTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ElevationOverlayTest.kt
index 7286991..90d0c21 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ElevationOverlayTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ElevationOverlayTest.kt
@@ -21,10 +21,11 @@
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.testutils.assertPixels
+import androidx.compose.testutils.assertPixelColor
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.graphics.toPixelMap
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.captureToImage
@@ -34,7 +35,6 @@
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.test.filters.LargeTest
-import androidx.test.filters.RequiresDevice
 import androidx.test.filters.SdkSuppress
 import org.junit.Rule
 import org.junit.Test
@@ -83,9 +83,12 @@
 
         rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                expectedSurfaceColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = expectedSurfaceColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
     @Test
@@ -105,12 +108,14 @@
 
         rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                expectedSurfaceColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = expectedSurfaceColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
-    @RequiresDevice // b/264705287
     @Test
     fun correctElevationOverlayWithCustomContentColor() {
         val customContentColor = Color.Blue
@@ -131,9 +136,12 @@
 
         rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                expectedSurfaceColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = expectedSurfaceColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
     @Test
@@ -149,9 +157,12 @@
 
         rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                expectedSurfaceColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = expectedSurfaceColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
     @Test
@@ -170,9 +181,12 @@
 
         rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                expectedSurfaceColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = expectedSurfaceColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
     @Test
@@ -181,7 +195,7 @@
 
         val customOverlay = object : ElevationOverlay {
             @Composable
-            override fun apply(color: Color, elevation: Dp): Color = Color.Red
+            override fun apply(color: Color, elevation: Dp): Color = customOverlayColor
         }
 
         rule.setContent {
@@ -190,12 +204,14 @@
             }
         }
 
-        rule
-            .onNodeWithTag(Tag)
+        rule.onNodeWithTag(Tag)
             .captureToImage()
-            .assertPixels(SurfaceSize) {
-                customOverlayColor
-            }
+            .toPixelMap()
+            .assertPixelColor(
+                expected = customOverlayColor,
+                x = SurfaceSize.width / 2,
+                y = SurfaceSize.height / 2
+            )
     }
 
     /**
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
index 1ded9e5..3c60de2 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SnackbarHostTest.kt
@@ -33,7 +33,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
-import androidx.test.filters.RequiresDevice
 import com.google.common.truth.Truth
 import com.nhaarman.mockitokotlin2.any
 import com.nhaarman.mockitokotlin2.doReturn
@@ -83,7 +82,6 @@
         rule.waitUntil { job.isCompleted }
     }
 
-    @RequiresDevice // b/264895456
     @Test
     fun snackbarHost_fifoQueueContract() {
         var resultedInvocation = ""
@@ -113,7 +111,6 @@
         Truth.assertThat(resultedInvocation).isEqualTo("0123456789")
     }
 
-    @RequiresDevice // b/264895456
     @Test
     @LargeTest
     fun snackbarHost_returnedResult() {
@@ -142,7 +139,7 @@
             Truth.assertThat(result).isEqualTo(SnackbarResult.Dismissed)
         }
 
-        rule.waitUntil(timeoutMillis = 5_000) { job2.isCompleted }
+        rule.waitUntil(timeoutMillis = 7_000) { job2.isCompleted }
     }
 
     @Test
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/pullrefresh/PullRefreshIndicator.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/pullrefresh/PullRefreshIndicator.kt
index 371e4cd..082cd36 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/pullrefresh/PullRefreshIndicator.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/pullrefresh/PullRefreshIndicator.kt
@@ -17,6 +17,8 @@
 package androidx.compose.material.pullrefresh
 
 import androidx.compose.animation.Crossfade
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.layout.Box
@@ -45,7 +47,6 @@
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.graphics.drawscope.rotate
-import androidx.compose.ui.semantics.contentDescription
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.dp
 import kotlin.math.abs
@@ -125,8 +126,18 @@
 ) {
     val path = remember { Path().apply { fillType = PathFillType.EvenOdd } }
 
-    Canvas(modifier.semantics { contentDescription = "Refreshing" }) {
+    val targetAlpha by remember(state) {
+        derivedStateOf {
+            if (state.progress >= 1f) MaxAlpha else MinAlpha
+        }
+    }
+
+    val alphaState = animateFloatAsState(targetValue = targetAlpha, animationSpec = AlphaTween)
+
+    // Empty semantics for tests
+    Canvas(modifier.semantics {}) {
         val values = ArrowValues(state.progress)
+        val alpha = alphaState.value
 
         rotate(degrees = values.rotation) {
             val arcRadius = ArcRadius.toPx() + StrokeWidth.toPx() / 2f
@@ -138,7 +149,7 @@
             )
             drawArc(
                 color = color,
-                alpha = values.alpha,
+                alpha = alpha,
                 startAngle = values.startAngle,
                 sweepAngle = values.endAngle - values.startAngle,
                 useCenter = false,
@@ -149,14 +160,13 @@
                     cap = StrokeCap.Square
                 )
             )
-            drawArrow(path, arcBounds, color, values)
+            drawArrow(path, arcBounds, color, alpha, values)
         }
     }
 }
 
 @Immutable
 private class ArrowValues(
-    val alpha: Float,
     val rotation: Float,
     val startAngle: Float,
     val endAngle: Float,
@@ -174,17 +184,22 @@
     val tensionPercent = linearTension - linearTension.pow(2) / 4
 
     // Calculations based on SwipeRefreshLayout specification.
-    val alpha = progress.coerceIn(0f, 1f)
     val endTrim = adjustedPercent * MaxProgressArc
     val rotation = (-0.25f + 0.4f * adjustedPercent + tensionPercent) * 0.5f
     val startAngle = rotation * 360
     val endAngle = (rotation + endTrim) * 360
     val scale = min(1f, adjustedPercent)
 
-    return ArrowValues(alpha, rotation, startAngle, endAngle, scale)
+    return ArrowValues(rotation, startAngle, endAngle, scale)
 }
 
-private fun DrawScope.drawArrow(arrow: Path, bounds: Rect, color: Color, values: ArrowValues) {
+private fun DrawScope.drawArrow(
+    arrow: Path,
+    bounds: Rect,
+    color: Color,
+    alpha: Float,
+    values: ArrowValues
+) {
     arrow.reset()
     arrow.moveTo(0f, 0f) // Move to left corner
     arrow.lineTo(x = ArrowWidth.toPx() * values.scale, y = 0f) // Line to right corner
@@ -205,7 +220,7 @@
     )
     arrow.close()
     rotate(degrees = values.endAngle) {
-        drawPath(path = arrow, color = color, alpha = values.alpha)
+        drawPath(path = arrow, color = color, alpha = alpha)
     }
 }
 
@@ -219,3 +234,8 @@
 private val ArrowWidth = 10.dp
 private val ArrowHeight = 5.dp
 private val Elevation = 6.dp
+
+// Values taken from SwipeRefreshLayout
+private const val MinAlpha = 0.3f
+private const val MaxAlpha = 1f
+private val AlphaTween = tween<Float>(300, easing = LinearEasing)
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 5508abe..cc495fc 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -34,6 +34,21 @@
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
+  public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+  }
+
   public final class BadgeKt {
   }
 
@@ -153,7 +168,20 @@
     method @androidx.compose.runtime.Composable 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.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
+  }
+
   public final class ChipKt {
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
   @androidx.compose.runtime.Stable public final class ColorScheme {
@@ -718,6 +746,21 @@
   public final class Strings_androidKt {
   }
 
+  public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index ad3d5cf..7a09faf 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -41,7 +41,7 @@
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TopAppBarState rememberTopAppBarState(optional float initialHeightOffsetLimit, optional float initialHeightOffset, optional float initialContentOffset);
   }
 
-  @androidx.compose.material3.ExperimentalMaterial3Api public final class AssistChipDefaults {
+  public final class AssistChipDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
@@ -201,23 +201,23 @@
     method @androidx.compose.runtime.Composable 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.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
-  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ChipBorder {
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
   }
 
-  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ChipColors {
+  @androidx.compose.runtime.Immutable public final class ChipColors {
   }
 
-  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class ChipElevation {
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
   }
 
   public final class ChipKt {
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedFilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, 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.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipColors colors, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
   @androidx.compose.runtime.Stable public final class ColorScheme {
@@ -739,8 +739,10 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class PlainTooltipState {
@@ -1026,7 +1028,7 @@
   public final class Strings_androidKt {
   }
 
-  @androidx.compose.material3.ExperimentalMaterial3Api public final class SuggestionChipDefaults {
+  public final class SuggestionChipDefaults {
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
     method public float getHeight();
@@ -1120,8 +1122,10 @@
   @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void FilledContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedBorderContainerBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<? extends kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit> container);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> container);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<? extends kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit> container);
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
     method public float getFocusedBorderThickness();
     method public float getMinHeight();
@@ -1129,9 +1133,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
     method public float getUnfocusedBorderThickness();
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional androidx.compose.foundation.text.selection.TextSelectionColors selectionColors, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor, optional long focusedSupportingTextColor, optional long unfocusedSupportingTextColor, optional long disabledSupportingTextColor, optional long errorSupportingTextColor, optional long focusedPrefixColor, optional long unfocusedPrefixColor, optional long disabledPrefixColor, optional long errorPrefixColor, optional long focusedSuffixColor, optional long unfocusedSuffixColor, optional long disabledSuffixColor, optional long errorSuffixColor);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
     property public final float FocusedBorderThickness;
@@ -1150,8 +1154,10 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? prefix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? suffix, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @Deprecated @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,? extends kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? trailingIcon, optional kotlin.jvm.functions.Function0<? extends kotlin.Unit>? supportingText, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional int minLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 5508abe..cc495fc 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -34,6 +34,21 @@
     method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional float tonalElevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.layout.WindowInsets windowInsets, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
+  public final class AssistChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder assistChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors assistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation assistChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedAssistChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedAssistChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.AssistChipDefaults INSTANCE;
+  }
+
   public final class BadgeKt {
   }
 
@@ -153,7 +168,20 @@
     method @androidx.compose.runtime.Composable 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.compose.material3.CheckboxColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  @androidx.compose.runtime.Immutable public final class ChipBorder {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipColors {
+  }
+
+  @androidx.compose.runtime.Immutable public final class ChipElevation {
+  }
+
   public final class ChipKt {
+    method @androidx.compose.runtime.Composable public static void AssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedAssistChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipColors colors, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
   @androidx.compose.runtime.Stable public final class ColorScheme {
@@ -718,6 +746,21 @@
   public final class Strings_androidKt {
   }
 
+  public final class SuggestionChipDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors elevatedSuggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation elevatedSuggestionChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method public float getHeight();
+    method public float getIconSize();
+    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getShape();
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder suggestionChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors suggestionChipColors(optional long containerColor, optional long labelColor, optional long iconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledIconContentColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation suggestionChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    property public final float Height;
+    property public final float IconSize;
+    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape shape;
+    field public static final androidx.compose.material3.SuggestionChipDefaults INSTANCE;
+  }
+
   public final class SurfaceKt {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.NonRestartableComposable public static void Surface(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.graphics.Shape shape, optional long color, optional long contentColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.ui.unit.Dp> getLocalAbsoluteTonalElevation();
diff --git a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
index f264ce1..093259d 100644
--- a/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
+++ b/compose/material3/material3/integration-tests/material3-catalog/src/main/java/androidx/compose/material3/catalog/library/model/Examples.kt
@@ -132,6 +132,7 @@
 import androidx.compose.material3.samples.TextFieldWithHideKeyboardOnImeAction
 import androidx.compose.material3.samples.TextFieldWithIcons
 import androidx.compose.material3.samples.TextFieldWithPlaceholder
+import androidx.compose.material3.samples.TextFieldWithPrefixAndSuffix
 import androidx.compose.material3.samples.TextFieldWithSupportingText
 import androidx.compose.material3.samples.TextTabs
 import androidx.compose.material3.samples.ThreeLineListItem
@@ -969,6 +970,13 @@
         TextFieldWithPlaceholder()
     },
     Example(
+        name = ::TextFieldWithPrefixAndSuffix.name,
+        description = TextFieldsExampleDescription,
+        sourceUrl = TextFieldsExampleSourceUrl
+    ) {
+        TextFieldWithPrefixAndSuffix()
+    },
+    Example(
         name = ::TextFieldWithErrorState.name,
         description = TextFieldsExampleDescription,
         sourceUrl = TextFieldsExampleSourceUrl
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
index 0a518f0..ffb2edf 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
@@ -51,7 +51,6 @@
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Preview
 @Sampled
 @Composable
@@ -69,7 +68,6 @@
     )
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Preview
 @Sampled
 @Composable
@@ -198,7 +196,6 @@
     )
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Preview
 @Sampled
 @Composable
@@ -209,7 +206,6 @@
     )
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Preview
 @Sampled
 @Composable
@@ -222,7 +218,6 @@
 
 @Preview
 @Sampled
-@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun ChipGroupSingleLineSample() {
     Column(horizontalAlignment = Alignment.CenterHorizontally) {
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
index 7cc188e..3231869 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
@@ -120,6 +120,23 @@
 @Preview
 @Sampled
 @Composable
+fun TextFieldWithPrefixAndSuffix() {
+    var text by rememberSaveable { mutableStateOf("") }
+
+    TextField(
+        value = text,
+        onValueChange = { text = it },
+        singleLine = true,
+        label = { Text("Label") },
+        prefix = { Text("www.") },
+        suffix = { Text(".com") },
+        placeholder = { Text("google") },
+    )
+}
+
+@Preview
+@Sampled
+@Composable
 fun TextFieldWithErrorState() {
     val errorMessage = "Text input too long"
     var text by rememberSaveable { mutableStateOf("") }
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
index 938e4be..c9c8f8b 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
@@ -598,6 +598,90 @@
     }
 
     @Test
+    fun outlinedTextField_prefixSuffix_withLabelAndInput() {
+        rule.setMaterialContent(lightColorScheme()) {
+            OutlinedTextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("outlinedTextField_prefixSuffix_withLabelAndInput")
+    }
+
+    @Test
+    fun outlinedTextField_prefixSuffix_withLabelAndInput_darkTheme() {
+        rule.setMaterialContent(darkColorScheme()) {
+            OutlinedTextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("outlinedTextField_prefixSuffix_withLabelAndInput_darkTheme")
+    }
+
+    @Test
+    fun outlinedTextField_prefixSuffix_withLabelAndInput_focused() {
+        rule.setMaterialContent(lightColorScheme()) {
+            OutlinedTextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        rule.onNodeWithTag(TextFieldTag).focus()
+
+        assertAgainstGolden("outlinedTextField_prefixSuffix_withLabelAndInput_focused")
+    }
+
+    @Test
+    fun outlinedTextField_prefixSuffix_withPlaceholder() {
+        rule.setMaterialContent(lightColorScheme()) {
+            OutlinedTextField(
+                value = "",
+                onValueChange = {},
+                placeholder = { Text("Placeholder") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("outlinedTextField_prefixSuffix_withPlaceholder")
+    }
+
+    @Test
+    fun outlinedTextField_prefixSuffix_withLeadingTrailingIcons() {
+        rule.setMaterialContent(lightColorScheme()) {
+            OutlinedTextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+                leadingIcon = { Icon(Icons.Default.Call, null) },
+                trailingIcon = { Icon(Icons.Default.Clear, null) },
+            )
+        }
+
+        assertAgainstGolden("outlinedTextField_prefixSuffix_withLeadingTrailingIcons")
+    }
+
+    @Test
     fun outlinedTextField_withInput_darkTheme() {
         rule.setMaterialContent(darkColorScheme()) {
             val text = "Text"
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
index 886e891c..ba87293 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
@@ -853,6 +853,176 @@
     }
 
     @Test
+    fun testOutlinedTextField_prefixAndSuffixPosition_withLabel() {
+        val textFieldWidth = 300.dp
+        val textFieldHeight = 60.dp
+        val labelSize = Ref<IntSize>()
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                OutlinedTextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(textFieldWidth, textFieldHeight),
+                    label = {
+                        Text(
+                            text = "label",
+                            modifier = Modifier.onGloballyPositioned {
+                                labelSize.value = it.size
+                            }
+                        )
+                    },
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(ExpectedPadding.toPx())
+                assertThat(prefixPosition.value?.y).isWithin(1f).of(
+                    (ExpectedPadding + 8.dp).toPx())
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (textFieldWidth - ExpectedPadding - suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y).isWithin(1f).of(
+                    (ExpectedPadding + 8.dp).toPx())
+            }
+        }
+    }
+
+    @Test
+    fun testOutlinedTextField_prefixAndSuffixPosition_whenNoLabel() {
+        val textFieldWidth = 300.dp
+        val textFieldHeight = 60.dp
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                OutlinedTextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(textFieldWidth, textFieldHeight),
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(ExpectedPadding.toPx())
+                assertThat(prefixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (textFieldWidth - ExpectedPadding - suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+            }
+        }
+    }
+
+    @Test
+    fun testOutlinedTextField_prefixAndSuffixPosition_withIcons() {
+        val textFieldWidth = 300.dp
+        val textFieldHeight = 60.dp
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                OutlinedTextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(textFieldWidth, textFieldHeight),
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    },
+                    leadingIcon = { Icon(Icons.Default.Favorite, null) },
+                    trailingIcon = { Icon(Icons.Default.Favorite, null) },
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                val iconSize = 24.dp // default icon size
+
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(
+                    (ExpectedPadding + IconPadding + iconSize).toPx())
+                assertThat(prefixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (textFieldWidth - IconPadding - iconSize - ExpectedPadding -
+                        suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+            }
+        }
+    }
+
+    @Test
     fun testOutlinedTextField_labelPositionX_initial_withTrailingAndLeading() {
         val labelPosition = Ref<Offset>()
         rule.setMaterialContent(lightColorScheme()) {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
index e10e87c..63f5771 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
@@ -589,6 +589,90 @@
     }
 
     @Test
+    fun textField_prefixSuffix_withLabelAndInput() {
+        rule.setMaterialContent(lightColorScheme()) {
+            TextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("textField_prefixSuffix_withLabelAndInput")
+    }
+
+    @Test
+    fun textField_prefixSuffix_withLabelAndInput_darkTheme() {
+        rule.setMaterialContent(darkColorScheme()) {
+            TextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("textField_prefixSuffix_withLabelAndInput_darkTheme")
+    }
+
+    @Test
+    fun textField_prefixSuffix_withLabelAndInput_focused() {
+        rule.setMaterialContent(lightColorScheme()) {
+            TextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        rule.onNodeWithTag(TextFieldTag).focus()
+
+        assertAgainstGolden("textField_prefixSuffix_withLabelAndInput_focused")
+    }
+
+    @Test
+    fun textField_prefixSuffix_withPlaceholder() {
+        rule.setMaterialContent(lightColorScheme()) {
+            TextField(
+                value = "",
+                onValueChange = {},
+                placeholder = { Text("Placeholder") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+            )
+        }
+
+        assertAgainstGolden("textField_prefixSuffix_withPlaceholder")
+    }
+
+    @Test
+    fun textField_prefixSuffix_withLeadingTrailingIcons() {
+        rule.setMaterialContent(lightColorScheme()) {
+            TextField(
+                value = "Text",
+                onValueChange = {},
+                label = { Text("Label") },
+                modifier = Modifier.width(300.dp).testTag(TextFieldTag),
+                prefix = { Text("P:") },
+                suffix = { Text(":S") },
+                leadingIcon = { Icon(Icons.Default.Call, null) },
+                trailingIcon = { Icon(Icons.Default.Clear, null) },
+            )
+        }
+
+        assertAgainstGolden("textField_prefixSuffix_withLeadingTrailingIcons")
+    }
+
+    @Test
     fun textField_withInput_darkTheme() {
         rule.setMaterialContent(darkColorScheme()) {
             Box(Modifier.semantics(mergeDescendants = true) {}.testTag(TextFieldTag)) {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
index 9bd61e2..bb7408a 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
@@ -867,6 +867,181 @@
     }
 
     @Test
+    fun testTextField_prefixAndSuffixPosition_withLabel() {
+        val textFieldHeight = 60.dp
+        val labelSize = Ref<IntSize>()
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                TextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(TextFieldWidth, textFieldHeight),
+                    label = {
+                        Text(
+                            text = "label",
+                            modifier = Modifier.onGloballyPositioned {
+                                labelSize.value = it.size
+                            }
+                        )
+                    },
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(ExpectedPadding.toPx())
+                assertThat(prefixPosition.value?.y)
+                    .isWithin(1f)
+                    .of(
+                        TextFieldWithLabelVerticalPadding.toPx() +
+                            labelSize.value!!.height.toFloat()
+                    )
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (TextFieldWidth - ExpectedPadding - suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y)
+                    .isWithin(1f)
+                    .of(
+                        TextFieldWithLabelVerticalPadding.toPx() +
+                            labelSize.value!!.height.toFloat()
+                    )
+            }
+        }
+    }
+
+    @Test
+    fun testTextField_prefixAndSuffixPosition_whenNoLabel() {
+        val textFieldHeight = 60.dp
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                TextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(TextFieldWidth, textFieldHeight),
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    }
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(ExpectedPadding.toPx())
+                assertThat(prefixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (TextFieldWidth - ExpectedPadding - suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+            }
+        }
+    }
+
+    @Test
+    fun testTextField_prefixAndSuffixPosition_withIcons() {
+        val textFieldHeight = 60.dp
+        val prefixPosition = Ref<Offset>()
+        val suffixPosition = Ref<Offset>()
+        val suffixSize = Ref<IntSize>()
+        val density = Density(2f)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            CompositionLocalProvider(LocalDensity provides density) {
+                TextField(
+                    value = "text",
+                    onValueChange = {},
+                    modifier = Modifier.size(TextFieldWidth, textFieldHeight),
+                    prefix = {
+                        Text(
+                            text = "P",
+                            modifier = Modifier.onGloballyPositioned {
+                                prefixPosition.value = it.positionInRoot()
+                            }
+                        )
+                    },
+                    suffix = {
+                        Text(
+                            text = "S",
+                            modifier = Modifier.onGloballyPositioned {
+                                suffixPosition.value = it.positionInRoot()
+                                suffixSize.value = it.size
+                            }
+                        )
+                    },
+                    leadingIcon = { Icon(Icons.Default.Favorite, null) },
+                    trailingIcon = { Icon(Icons.Default.Favorite, null) },
+                )
+            }
+        }
+
+        rule.runOnIdle {
+            with(density) {
+                val iconSize = 24.dp // default icon size
+
+                // prefix
+                assertThat(prefixPosition.value?.x).isWithin(1f).of(
+                    (ExpectedPadding + IconPadding + iconSize).toPx())
+                assertThat(prefixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+
+                // suffix
+                assertThat(suffixPosition.value?.x).isWithin(1f).of(
+                    (TextFieldWidth - IconPadding - iconSize - ExpectedPadding -
+                        suffixSize.value!!.width.toDp()).toPx()
+                )
+                assertThat(suffixPosition.value?.y).isWithin(1f).of(ExpectedPadding.toPx())
+            }
+        }
+    }
+
+    @Test
     fun testTextField_labelPositionX_initial_withTrailingAndLeading() {
         val height = 60.dp
         val labelPosition = Ref<Offset>()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
index 0b7e31c..6ad4b7a 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
@@ -100,7 +100,6 @@
  * 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.
  */
-@ExperimentalMaterial3Api
 @Composable
 fun AssistChip(
     onClick: () -> Unit,
@@ -172,7 +171,6 @@
  * 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.
  */
-@ExperimentalMaterial3Api
 @Composable
 fun ElevatedAssistChip(
     onClick: () -> Unit,
@@ -516,7 +514,6 @@
  * 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.
  */
-@ExperimentalMaterial3Api
 @Composable
 fun SuggestionChip(
     onClick: () -> Unit,
@@ -585,7 +582,6 @@
  * 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.
  */
-@ExperimentalMaterial3Api
 @Composable
 fun ElevatedSuggestionChip(
     onClick: () -> Unit,
@@ -619,7 +615,6 @@
 /**
  * Contains the baseline values used by [AssistChip].
  */
-@ExperimentalMaterial3Api
 object AssistChipDefaults {
     /**
      * The height applied for an assist chip.
@@ -1142,7 +1137,6 @@
 /**
  * Contains the baseline values used by [SuggestionChip].
  */
-@ExperimentalMaterial3Api
 object SuggestionChipDefaults {
     /**
      * The height applied for a suggestion chip.
@@ -1304,7 +1298,7 @@
     val shape: Shape @Composable get() = SuggestionChipTokens.ContainerShape.toShape()
 }
 
-@ExperimentalMaterial3Api
+@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 private fun Chip(
     modifier: Modifier,
@@ -1445,7 +1439,6 @@
 /**
  * Represents the elevation for a chip in different states.
  */
-@ExperimentalMaterial3Api
 @Immutable
 class ChipElevation internal constructor(
     private val defaultElevation: Dp,
@@ -1764,7 +1757,6 @@
  * See [AssistChipDefaults], [InputChipDefaults], and [SuggestionChipDefaults] for the default
  * colors used in the various Chip configurations.
  */
-@ExperimentalMaterial3Api
 @Immutable
 class ChipColors internal constructor(
     private val containerColor: Color,
@@ -2040,7 +2032,6 @@
 /**
  * Represents the border stroke used in a chip in different states.
  */
-@ExperimentalMaterial3Api
 @Immutable
 class ChipBorder internal constructor(
     private val borderColor: Color,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
index ad3cff5..daf88f2 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
@@ -103,6 +103,8 @@
  * container
  * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
  * container
+ * @param prefix the optional prefix to be displayed before the input text in the text field
+ * @param suffix the optional suffix to be displayed after the input text in the text field
  * @param supportingText the optional supporting text to be displayed below the text field
  * @param isError indicates if the text field's current value is in error. If set to true, the
  * label, bottom indicator and trailing icon by default will be displayed in error color
@@ -143,6 +145,8 @@
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
+    prefix: @Composable (() -> Unit)? = null,
+    suffix: @Composable (() -> Unit)? = null,
     supportingText: @Composable (() -> Unit)? = null,
     isError: Boolean = false,
     visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -199,6 +203,8 @@
                     label = label,
                     leadingIcon = leadingIcon,
                     trailingIcon = trailingIcon,
+                    prefix = prefix,
+                    suffix = suffix,
                     supportingText = supportingText,
                     singleLine = singleLine,
                     enabled = enabled,
@@ -257,6 +263,8 @@
  * container
  * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
  * container
+ * @param prefix the optional prefix to be displayed before the input text in the text field
+ * @param suffix the optional suffix to be displayed after the input text in the text field
  * @param supportingText the optional supporting text to be displayed below the text field
  * @param isError indicates if the text field's current value is in error state. If set to
  * true, the label, bottom indicator and trailing icon by default will be displayed in error color
@@ -297,6 +305,8 @@
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
+    prefix: @Composable (() -> Unit)? = null,
+    suffix: @Composable (() -> Unit)? = null,
     supportingText: @Composable (() -> Unit)? = null,
     isError: Boolean = false,
     visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -353,6 +363,8 @@
                     label = label,
                     leadingIcon = leadingIcon,
                     trailingIcon = trailingIcon,
+                    prefix = prefix,
+                    suffix = suffix,
                     supportingText = supportingText,
                     singleLine = singleLine,
                     enabled = enabled,
@@ -374,6 +386,112 @@
     }
 }
 
+@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+@ExperimentalMaterial3Api
+@Composable
+fun OutlinedTextField(
+    value: String,
+    onValueChange: (String) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    readOnly: Boolean = false,
+    textStyle: TextStyle = LocalTextStyle.current,
+    label: @Composable (() -> Unit)? = null,
+    placeholder: @Composable (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    supportingText: @Composable (() -> Unit)? = null,
+    isError: Boolean = false,
+    visualTransformation: VisualTransformation = VisualTransformation.None,
+    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+    keyboardActions: KeyboardActions = KeyboardActions.Default,
+    singleLine: Boolean = false,
+    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+    minLines: Int = 1,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    shape: Shape = TextFieldDefaults.outlinedShape,
+    colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
+) {
+    OutlinedTextField(
+        value = value,
+        onValueChange = onValueChange,
+        modifier = modifier,
+        enabled = enabled,
+        readOnly = readOnly,
+        textStyle = textStyle,
+        label = label,
+        placeholder = placeholder,
+        leadingIcon = leadingIcon,
+        trailingIcon = trailingIcon,
+        prefix = null,
+        suffix = null,
+        supportingText = supportingText,
+        isError = isError,
+        visualTransformation = visualTransformation,
+        keyboardOptions = keyboardOptions,
+        keyboardActions = keyboardActions,
+        singleLine = singleLine,
+        maxLines = maxLines,
+        minLines = minLines,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+    )
+}
+
+@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+@ExperimentalMaterial3Api
+@Composable
+fun OutlinedTextField(
+    value: TextFieldValue,
+    onValueChange: (TextFieldValue) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    readOnly: Boolean = false,
+    textStyle: TextStyle = LocalTextStyle.current,
+    label: @Composable (() -> Unit)? = null,
+    placeholder: @Composable (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    supportingText: @Composable (() -> Unit)? = null,
+    isError: Boolean = false,
+    visualTransformation: VisualTransformation = VisualTransformation.None,
+    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+    keyboardActions: KeyboardActions = KeyboardActions.Default,
+    singleLine: Boolean = false,
+    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+    minLines: Int = 1,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    shape: Shape = TextFieldDefaults.outlinedShape,
+    colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
+) {
+    OutlinedTextField(
+        value = value,
+        onValueChange = onValueChange,
+        modifier = modifier,
+        enabled = enabled,
+        readOnly = readOnly,
+        textStyle = textStyle,
+        label = label,
+        placeholder = placeholder,
+        leadingIcon = leadingIcon,
+        trailingIcon = trailingIcon,
+        prefix = null,
+        suffix = null,
+        supportingText = supportingText,
+        isError = isError,
+        visualTransformation = visualTransformation,
+        keyboardOptions = keyboardOptions,
+        keyboardActions = keyboardActions,
+        singleLine = singleLine,
+        maxLines = maxLines,
+        minLines = minLines,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+    )
+}
+
 /**
  * Layout of the leading and trailing icons and the text field, label and placeholder in
  * [OutlinedTextField].
@@ -389,6 +507,8 @@
     label: @Composable (() -> Unit)?,
     leading: @Composable (() -> Unit)?,
     trailing: @Composable (() -> Unit)?,
+    prefix: @Composable (() -> Unit)?,
+    suffix: @Composable (() -> Unit)?,
     singleLine: Boolean,
     animationProgress: Float,
     onLabelMeasured: (Size) -> Unit,
@@ -429,26 +549,48 @@
 
             val startTextFieldPadding = paddingValues.calculateStartPadding(layoutDirection)
             val endTextFieldPadding = paddingValues.calculateEndPadding(layoutDirection)
-            val padding = Modifier.padding(
-                start = if (leading != null) {
-                    (startTextFieldPadding - HorizontalIconPadding).coerceAtLeast(
-                        0.dp
-                    )
-                } else {
-                    startTextFieldPadding
-                },
-                end = if (trailing != null) {
-                    (endTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
-                } else {
-                    endTextFieldPadding
+
+            val startPadding = if (leading != null) {
+                (startTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
+            } else {
+                startTextFieldPadding
+            }
+            val endPadding = if (trailing != null) {
+                (endTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
+            } else {
+                endTextFieldPadding
+            }
+
+            if (prefix != null) {
+                Box(
+                    Modifier
+                        .layoutId(PrefixId)
+                        .padding(start = startPadding, end = PrefixSuffixTextPadding)
+                ) {
+                    prefix()
                 }
+            }
+            if (suffix != null) {
+                Box(
+                    Modifier
+                        .layoutId(SuffixId)
+                        .padding(start = PrefixSuffixTextPadding, end = endPadding)
+                ) {
+                    suffix()
+                }
+            }
+
+            val textPadding = Modifier.padding(
+                start = if (prefix == null) startPadding else 0.dp,
+                end = if (suffix == null) endPadding else 0.dp,
             )
+
             if (placeholder != null) {
-                placeholder(Modifier.layoutId(PlaceholderId).then(padding))
+                placeholder(Modifier.layoutId(PlaceholderId).then(textPadding))
             }
 
             Box(
-                modifier = Modifier.layoutId(TextFieldId).then(padding),
+                modifier = Modifier.layoutId(TextFieldId).then(textPadding),
                 propagateMinConstraints = true
             ) {
                 textField()
@@ -489,19 +631,27 @@
         val leadingPlaceable = measurables.find {
             it.layoutId == LeadingId
         }?.measure(relaxedConstraints)
-        occupiedSpaceHorizontally += widthOrZero(
-            leadingPlaceable
-        )
+        occupiedSpaceHorizontally += widthOrZero(leadingPlaceable)
         occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(leadingPlaceable))
 
         // measure trailing icon
         val trailingPlaceable = measurables.find { it.layoutId == TrailingId }
             ?.measure(relaxedConstraints.offset(horizontal = -occupiedSpaceHorizontally))
-        occupiedSpaceHorizontally += widthOrZero(
-            trailingPlaceable
-        )
+        occupiedSpaceHorizontally += widthOrZero(trailingPlaceable)
         occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(trailingPlaceable))
 
+        // measure prefix
+        val prefixPlaceable = measurables.find { it.layoutId == PrefixId }
+            ?.measure(relaxedConstraints.offset(horizontal = -occupiedSpaceHorizontally))
+        occupiedSpaceHorizontally += widthOrZero(prefixPlaceable)
+        occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(prefixPlaceable))
+
+        // measure suffix
+        val suffixPlaceable = measurables.find { it.layoutId == SuffixId }
+            ?.measure(relaxedConstraints.offset(horizontal = -occupiedSpaceHorizontally))
+        occupiedSpaceHorizontally += widthOrZero(suffixPlaceable)
+        occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(suffixPlaceable))
+
         // measure label
         val isLabelInMiddleSection = animationProgress < 1f
         val labelHorizontalPaddingOffset =
@@ -559,6 +709,8 @@
             calculateWidth(
                 leadingPlaceableWidth = widthOrZero(leadingPlaceable),
                 trailingPlaceableWidth = widthOrZero(trailingPlaceable),
+                prefixPlaceableWidth = widthOrZero(prefixPlaceable),
+                suffixPlaceableWidth = widthOrZero(suffixPlaceable),
                 textFieldPlaceableWidth = textFieldPlaceable.width,
                 labelPlaceableWidth = widthOrZero(labelPlaceable),
                 placeholderPlaceableWidth = widthOrZero(placeholderPlaceable),
@@ -569,15 +721,17 @@
             )
         val totalHeight =
             calculateHeight(
-                heightOrZero(leadingPlaceable),
-                heightOrZero(trailingPlaceable),
-                textFieldPlaceable.height,
-                heightOrZero(labelPlaceable),
-                heightOrZero(placeholderPlaceable),
-                heightOrZero(supportingPlaceable),
-                constraints,
-                density,
-                paddingValues
+                leadingPlaceableHeight = heightOrZero(leadingPlaceable),
+                trailingPlaceableHeight = heightOrZero(trailingPlaceable),
+                prefixPlaceableHeight = heightOrZero(prefixPlaceable),
+                suffixPlaceableHeight = heightOrZero(suffixPlaceable),
+                textFieldPlaceableHeight = textFieldPlaceable.height,
+                labelPlaceableHeight = heightOrZero(labelPlaceable),
+                placeholderPlaceableHeight = heightOrZero(placeholderPlaceable),
+                supportingPlaceableHeight = heightOrZero(supportingPlaceable),
+                constraints = constraints,
+                density = density,
+                paddingValues = paddingValues,
             )
         val height = totalHeight - supportingHeight
 
@@ -591,20 +745,22 @@
         )
         return layout(width, totalHeight) {
             place(
-                totalHeight,
-                width,
-                leadingPlaceable,
-                trailingPlaceable,
-                textFieldPlaceable,
-                labelPlaceable,
-                placeholderPlaceable,
-                containerPlaceable,
-                supportingPlaceable,
-                animationProgress,
-                singleLine,
-                density,
-                layoutDirection,
-                paddingValues
+                totalHeight = totalHeight,
+                width = width,
+                leadingPlaceable = leadingPlaceable,
+                trailingPlaceable = trailingPlaceable,
+                prefixPlaceable = prefixPlaceable,
+                suffixPlaceable = suffixPlaceable,
+                textFieldPlaceable = textFieldPlaceable,
+                labelPlaceable = labelPlaceable,
+                placeholderPlaceable = placeholderPlaceable,
+                containerPlaceable = containerPlaceable,
+                supportingPlaceable = supportingPlaceable,
+                animationProgress = animationProgress,
+                singleLine = singleLine,
+                density = density,
+                layoutDirection = layoutDirection,
+                paddingValues = paddingValues,
             )
         }
     }
@@ -661,12 +817,20 @@
         val leadingWidth = measurables.find { it.layoutId == LeadingId }?.let {
             intrinsicMeasurer(it, height)
         } ?: 0
+        val prefixWidth = measurables.find { it.layoutId == PrefixId }?.let {
+            intrinsicMeasurer(it, height)
+        } ?: 0
+        val suffixWidth = measurables.find { it.layoutId == SuffixId }?.let {
+            intrinsicMeasurer(it, height)
+        } ?: 0
         val placeholderWidth = measurables.find { it.layoutId == PlaceholderId }?.let {
             intrinsicMeasurer(it, height)
         } ?: 0
         return calculateWidth(
             leadingPlaceableWidth = leadingWidth,
             trailingPlaceableWidth = trailingWidth,
+            prefixPlaceableWidth = prefixWidth,
+            suffixPlaceableWidth = suffixWidth,
             textFieldPlaceableWidth = textFieldWidth,
             labelPlaceableWidth = labelWidth,
             placeholderPlaceableWidth = placeholderWidth,
@@ -693,6 +857,12 @@
         val leadingHeight = measurables.find { it.layoutId == LeadingId }?.let {
             intrinsicMeasurer(it, width)
         } ?: 0
+        val prefixHeight = measurables.find { it.layoutId == PrefixId }?.let {
+            intrinsicMeasurer(it, width)
+        } ?: 0
+        val suffixHeight = measurables.find { it.layoutId == SuffixId }?.let {
+            intrinsicMeasurer(it, width)
+        } ?: 0
         val placeholderHeight = measurables.find { it.layoutId == PlaceholderId }?.let {
             intrinsicMeasurer(it, width)
         } ?: 0
@@ -702,6 +872,8 @@
         return calculateHeight(
             leadingPlaceableHeight = leadingHeight,
             trailingPlaceableHeight = trailingHeight,
+            prefixPlaceableHeight = prefixHeight,
+            suffixPlaceableHeight = suffixHeight,
             textFieldPlaceableHeight = textFieldHeight,
             labelPlaceableHeight = labelHeight,
             placeholderPlaceableHeight = placeholderHeight,
@@ -719,6 +891,8 @@
 private fun calculateWidth(
     leadingPlaceableWidth: Int,
     trailingPlaceableWidth: Int,
+    prefixPlaceableWidth: Int,
+    suffixPlaceableWidth: Int,
     textFieldPlaceableWidth: Int,
     labelPlaceableWidth: Int,
     placeholderPlaceableWidth: Int,
@@ -727,10 +901,12 @@
     density: Float,
     paddingValues: PaddingValues,
 ): Int {
+    val affixTotalWidth = prefixPlaceableWidth + suffixPlaceableWidth
     val middleSection = maxOf(
-        textFieldPlaceableWidth,
+        textFieldPlaceableWidth + affixTotalWidth,
+        placeholderPlaceableWidth + affixTotalWidth,
+        // Prefix/suffix does not get applied to label
         if (isLabelInMiddleSection) labelPlaceableWidth else 0,
-        placeholderPlaceableWidth
     )
     val wrappedWidth =
         leadingPlaceableWidth + middleSection + trailingPlaceableWidth
@@ -754,6 +930,8 @@
 private fun calculateHeight(
     leadingPlaceableHeight: Int,
     trailingPlaceableHeight: Int,
+    prefixPlaceableHeight: Int,
+    suffixPlaceableHeight: Int,
     textFieldPlaceableHeight: Int,
     labelPlaceableHeight: Int,
     placeholderPlaceableHeight: Int,
@@ -780,6 +958,8 @@
         maxOf(
             leadingPlaceableHeight,
             trailingPlaceableHeight,
+            prefixPlaceableHeight,
+            suffixPlaceableHeight,
             middleSectionHeight.roundToInt()
         ) + supportingPlaceableHeight
     )
@@ -794,6 +974,8 @@
     width: Int,
     leadingPlaceable: Placeable?,
     trailingPlaceable: Placeable?,
+    prefixPlaceable: Placeable?,
+    suffixPlaceable: Placeable?,
     textFieldPlaceable: Placeable,
     labelPlaceable: Placeable?,
     placeholderPlaceable: Placeable?,
@@ -830,7 +1012,7 @@
     )
 
     // label position is animated
-    // in single line text field label is centered vertically before animation starts
+    // in single line text field, label is centered vertically before animation starts
     var labelPositionY: Int? = null
     labelPlaceable?.let {
         val startPositionY = if (singleLine) {
@@ -850,38 +1032,51 @@
         it.placeRelative(positionX, positionY)
     }
 
-    // placed center vertically and after the leading icon horizontally if single line text field
-    // placed to the top with padding for multi line text field
-    val textVerticalPosition = max(
-        if (singleLine) {
-            Alignment.CenterVertically.align(textFieldPlaceable.height, height)
-        } else {
-            topPadding
-        },
-        heightOrZero(labelPlaceable) / 2
-    )
-    textFieldPlaceable.placeRelative(widthOrZero(leadingPlaceable), textVerticalPosition)
-
-    // placed similar to the input text above
-    placeholderPlaceable?.let {
-        var placeholderVerticalPosition = max(
+    // Single line text fields have text components centered vertically.
+    // Multiline text fields have text components aligned to top with padding.
+    fun calculateVerticalPosition(placeable: Placeable): Int {
+        val verticalPosition = max(
             if (singleLine) {
-                Alignment.CenterVertically.align(it.height, height)
+                Alignment.CenterVertically.align(placeable.height, height)
             } else {
                 topPadding
             },
             heightOrZero(labelPlaceable) / 2
         )
-        // Ensure placeholder's bounding box does not cover label in unfocused state
+
+        // Ensure placeable's bounding box does not cover label in unfocused state
         // (workaround for b/261061240)
         labelPositionY?.let { labelPositionY ->
-            if (placeholderVerticalPosition <= labelPositionY) {
-                placeholderVerticalPosition = labelPositionY + 1
+            if (verticalPosition <= labelPositionY) {
+                return labelPositionY + 1
             }
         }
-        it.placeRelative(widthOrZero(leadingPlaceable), placeholderVerticalPosition)
+        return verticalPosition
     }
 
+    prefixPlaceable?.placeRelative(
+        widthOrZero(leadingPlaceable),
+        calculateVerticalPosition(prefixPlaceable)
+    )
+
+    suffixPlaceable?.placeRelative(
+        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
+        calculateVerticalPosition(suffixPlaceable)
+    )
+
+    val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
+
+    textFieldPlaceable.placeRelative(
+        textHorizontalPosition,
+        calculateVerticalPosition(textFieldPlaceable)
+    )
+
+    // placed similar to the input text above
+    placeholderPlaceable?.placeRelative(
+        textHorizontalPosition,
+        calculateVerticalPosition(placeholderPlaceable)
+    )
+
     // place supporting text
     supportingPlaceable?.placeRelative(0, height)
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index c3c6808..547fb09 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -86,6 +86,10 @@
  *
  * @sample androidx.compose.material3.samples.TextFieldWithIcons
  *
+ * You can also provide a prefix or suffix to the text:
+ *
+ * @sample androidx.compose.material3.samples.TextFieldWithPrefixAndSuffix
+ *
  * To handle the error input state, use [isError] parameter:
  *
  * @sample androidx.compose.material3.samples.TextFieldWithErrorState
@@ -125,6 +129,8 @@
  * container
  * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
  * container
+ * @param prefix the optional prefix to be displayed before the input text in the text field
+ * @param suffix the optional suffix to be displayed after the input text in the text field
  * @param supportingText the optional supporting text to be displayed below the text field
  * @param isError indicates if the text field's current value is in error. If set to true, the
  * label, bottom indicator and trailing icon by default will be displayed in error color
@@ -165,6 +171,8 @@
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
+    prefix: @Composable (() -> Unit)? = null,
+    suffix: @Composable (() -> Unit)? = null,
     supportingText: @Composable (() -> Unit)? = null,
     isError: Boolean = false,
     visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -214,6 +222,8 @@
                     label = label,
                     leadingIcon = leadingIcon,
                     trailingIcon = trailingIcon,
+                    prefix = prefix,
+                    suffix = suffix,
                     supportingText = supportingText,
                     shape = shape,
                     singleLine = singleLine,
@@ -265,6 +275,8 @@
  * container
  * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
  * container
+ * @param prefix the optional prefix to be displayed before the input text in the text field
+ * @param suffix the optional suffix to be displayed after the input text in the text field
  * @param supportingText the optional supporting text to be displayed below the text field
  * @param isError indicates if the text field's current value is in error state. If set to
  * true, the label, bottom indicator and trailing icon by default will be displayed in error color
@@ -305,6 +317,8 @@
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
+    prefix: @Composable (() -> Unit)? = null,
+    suffix: @Composable (() -> Unit)? = null,
     supportingText: @Composable (() -> Unit)? = null,
     isError: Boolean = false,
     visualTransformation: VisualTransformation = VisualTransformation.None,
@@ -354,6 +368,8 @@
                     label = label,
                     leadingIcon = leadingIcon,
                     trailingIcon = trailingIcon,
+                    prefix = prefix,
+                    suffix = suffix,
                     supportingText = supportingText,
                     shape = shape,
                     singleLine = singleLine,
@@ -367,6 +383,112 @@
     }
 }
 
+@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+@ExperimentalMaterial3Api
+@Composable
+fun TextField(
+    value: String,
+    onValueChange: (String) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    readOnly: Boolean = false,
+    textStyle: TextStyle = LocalTextStyle.current,
+    label: @Composable (() -> Unit)? = null,
+    placeholder: @Composable (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    supportingText: @Composable (() -> Unit)? = null,
+    isError: Boolean = false,
+    visualTransformation: VisualTransformation = VisualTransformation.None,
+    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+    keyboardActions: KeyboardActions = KeyboardActions.Default,
+    singleLine: Boolean = false,
+    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+    minLines: Int = 1,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    shape: Shape = TextFieldDefaults.filledShape,
+    colors: TextFieldColors = TextFieldDefaults.textFieldColors()
+) {
+    TextField(
+        value = value,
+        onValueChange = onValueChange,
+        modifier = modifier,
+        enabled = enabled,
+        readOnly = readOnly,
+        textStyle = textStyle,
+        label = label,
+        placeholder = placeholder,
+        leadingIcon = leadingIcon,
+        trailingIcon = trailingIcon,
+        prefix = null,
+        suffix = null,
+        supportingText = supportingText,
+        isError = isError,
+        visualTransformation = visualTransformation,
+        keyboardOptions = keyboardOptions,
+        keyboardActions = keyboardActions,
+        singleLine = singleLine,
+        maxLines = maxLines,
+        minLines = minLines,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+    )
+}
+
+@Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+@ExperimentalMaterial3Api
+@Composable
+fun TextField(
+    value: TextFieldValue,
+    onValueChange: (TextFieldValue) -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    readOnly: Boolean = false,
+    textStyle: TextStyle = LocalTextStyle.current,
+    label: @Composable (() -> Unit)? = null,
+    placeholder: @Composable (() -> Unit)? = null,
+    leadingIcon: @Composable (() -> Unit)? = null,
+    trailingIcon: @Composable (() -> Unit)? = null,
+    supportingText: @Composable (() -> Unit)? = null,
+    isError: Boolean = false,
+    visualTransformation: VisualTransformation = VisualTransformation.None,
+    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
+    keyboardActions: KeyboardActions = KeyboardActions.Default,
+    singleLine: Boolean = false,
+    maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
+    minLines: Int = 1,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    shape: Shape = TextFieldDefaults.filledShape,
+    colors: TextFieldColors = TextFieldDefaults.textFieldColors()
+) {
+    TextField(
+        value = value,
+        onValueChange = onValueChange,
+        modifier = modifier,
+        enabled = enabled,
+        readOnly = readOnly,
+        textStyle = textStyle,
+        label = label,
+        placeholder = placeholder,
+        leadingIcon = leadingIcon,
+        trailingIcon = trailingIcon,
+        prefix = null,
+        suffix = null,
+        supportingText = supportingText,
+        isError = isError,
+        visualTransformation = visualTransformation,
+        keyboardOptions = keyboardOptions,
+        keyboardActions = keyboardActions,
+        singleLine = singleLine,
+        maxLines = maxLines,
+        minLines = minLines,
+        interactionSource = interactionSource,
+        shape = shape,
+        colors = colors,
+    )
+}
+
 /**
  * Composable responsible for measuring and laying out leading and trailing icons, label,
  * placeholder and the input field.
@@ -380,6 +502,8 @@
     placeholder: @Composable ((Modifier) -> Unit)?,
     leading: @Composable (() -> Unit)?,
     trailing: @Composable (() -> Unit)?,
+    prefix: @Composable (() -> Unit)?,
+    suffix: @Composable (() -> Unit)?,
     singleLine: Boolean,
     animationProgress: Float,
     container: @Composable () -> Unit,
@@ -421,36 +545,54 @@
 
             val startTextFieldPadding = paddingValues.calculateStartPadding(layoutDirection)
             val endTextFieldPadding = paddingValues.calculateEndPadding(layoutDirection)
-            val padding = Modifier.padding(
-                start = if (leading != null) {
-                    (startTextFieldPadding - HorizontalIconPadding).coerceAtLeast(
-                        0.dp
-                    )
-                } else {
-                    startTextFieldPadding
-                },
-                end = if (trailing != null) {
-                    (endTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
-                } else {
-                    endTextFieldPadding
-                }
-            )
-            if (placeholder != null) {
-                placeholder(
-                    Modifier
-                        .layoutId(PlaceholderId)
-                        .then(padding))
+
+            val startPadding = if (leading != null) {
+                (startTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
+            } else {
+                startTextFieldPadding
             }
+            val endPadding = if (trailing != null) {
+                (endTextFieldPadding - HorizontalIconPadding).coerceAtLeast(0.dp)
+            } else {
+                endTextFieldPadding
+            }
+
+            if (prefix != null) {
+                Box(
+                    Modifier
+                        .layoutId(PrefixId)
+                        .padding(start = startPadding, end = PrefixSuffixTextPadding)
+                ) {
+                    prefix()
+                }
+            }
+            if (suffix != null) {
+                Box(
+                    Modifier
+                        .layoutId(SuffixId)
+                        .padding(start = PrefixSuffixTextPadding, end = endPadding)
+                ) {
+                    suffix()
+                }
+            }
+
             if (label != null) {
                 Box(
                     Modifier
                         .layoutId(LabelId)
-                        .then(padding)) { label() }
+                        .padding(start = startPadding, end = endPadding)) { label() }
+            }
+
+            val textPadding = Modifier.padding(
+                start = if (prefix == null) startPadding else 0.dp,
+                end = if (suffix == null) endPadding else 0.dp,
+            )
+
+            if (placeholder != null) {
+                placeholder(Modifier.layoutId(PlaceholderId).then(textPadding))
             }
             Box(
-                modifier = Modifier
-                    .layoutId(TextFieldId)
-                    .then(padding),
+                modifier = Modifier.layoutId(TextFieldId).then(textPadding),
                 propagateMinConstraints = true,
             ) {
                 textField()
@@ -487,19 +629,27 @@
         // measure leading icon
         val leadingPlaceable =
             measurables.find { it.layoutId == LeadingId }?.measure(looseConstraints)
-        occupiedSpaceHorizontally += widthOrZero(
-            leadingPlaceable
-        )
+        occupiedSpaceHorizontally += widthOrZero(leadingPlaceable)
         occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(leadingPlaceable))
 
         // measure trailing icon
         val trailingPlaceable = measurables.find { it.layoutId == TrailingId }
             ?.measure(looseConstraints.offset(horizontal = -occupiedSpaceHorizontally))
-        occupiedSpaceHorizontally += widthOrZero(
-            trailingPlaceable
-        )
+        occupiedSpaceHorizontally += widthOrZero(trailingPlaceable)
         occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(trailingPlaceable))
 
+        // measure prefix
+        val prefixPlaceable = measurables.find { it.layoutId == PrefixId }
+            ?.measure(looseConstraints.offset(horizontal = -occupiedSpaceHorizontally))
+        occupiedSpaceHorizontally += widthOrZero(prefixPlaceable)
+        occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(prefixPlaceable))
+
+        // measure suffix
+        val suffixPlaceable = measurables.find { it.layoutId == SuffixId }
+            ?.measure(looseConstraints.offset(horizontal = -occupiedSpaceHorizontally))
+        occupiedSpaceHorizontally += widthOrZero(suffixPlaceable)
+        occupiedSpaceVertically = max(occupiedSpaceVertically, heightOrZero(suffixPlaceable))
+
         // measure label
         val labelConstraints = looseConstraints
             .offset(
@@ -545,6 +695,8 @@
         val width = calculateWidth(
             leadingWidth = widthOrZero(leadingPlaceable),
             trailingWidth = widthOrZero(trailingPlaceable),
+            prefixWidth = widthOrZero(prefixPlaceable),
+            suffixWidth = widthOrZero(suffixPlaceable),
             textFieldWidth = textFieldPlaceable.width,
             labelWidth = widthOrZero(labelPlaceable),
             placeholderWidth = widthOrZero(placeholderPlaceable),
@@ -555,6 +707,8 @@
             labelHeight = heightOrZero(labelPlaceable),
             leadingHeight = heightOrZero(leadingPlaceable),
             trailingHeight = heightOrZero(trailingPlaceable),
+            prefixHeight = heightOrZero(prefixPlaceable),
+            suffixHeight = heightOrZero(suffixPlaceable),
             placeholderHeight = heightOrZero(placeholderPlaceable),
             supportingHeight = heightOrZero(supportingPlaceable),
             isLabelFocused = animationProgress == 1f,
@@ -583,6 +737,8 @@
                     placeholderPlaceable = placeholderPlaceable,
                     leadingPlaceable = leadingPlaceable,
                     trailingPlaceable = trailingPlaceable,
+                    prefixPlaceable = prefixPlaceable,
+                    suffixPlaceable = suffixPlaceable,
                     containerPlaceable = containerPlaceable,
                     supportingPlaceable = supportingPlaceable,
                     singleLine = singleLine,
@@ -599,6 +755,8 @@
                     placeholderPlaceable = placeholderPlaceable,
                     leadingPlaceable = leadingPlaceable,
                     trailingPlaceable = trailingPlaceable,
+                    prefixPlaceable = prefixPlaceable,
+                    suffixPlaceable = suffixPlaceable,
                     containerPlaceable = containerPlaceable,
                     supportingPlaceable = supportingPlaceable,
                     singleLine = singleLine,
@@ -658,6 +816,12 @@
         val trailingWidth = measurables.find { it.layoutId == TrailingId }?.let {
             intrinsicMeasurer(it, height)
         } ?: 0
+        val prefixWidth = measurables.find { it.layoutId == PrefixId }?.let {
+            intrinsicMeasurer(it, height)
+        } ?: 0
+        val suffixWidth = measurables.find { it.layoutId == SuffixId }?.let {
+            intrinsicMeasurer(it, height)
+        } ?: 0
         val leadingWidth = measurables.find { it.layoutId == LeadingId }?.let {
             intrinsicMeasurer(it, height)
         } ?: 0
@@ -667,6 +831,8 @@
         return calculateWidth(
             leadingWidth = leadingWidth,
             trailingWidth = trailingWidth,
+            prefixWidth = prefixWidth,
+            suffixWidth = suffixWidth,
             textFieldWidth = textFieldWidth,
             labelWidth = labelWidth,
             placeholderWidth = placeholderWidth,
@@ -690,6 +856,12 @@
         val leadingHeight = measurables.find { it.layoutId == LeadingId }?.let {
             intrinsicMeasurer(it, width)
         } ?: 0
+        val prefixHeight = measurables.find { it.layoutId == PrefixId }?.let {
+            intrinsicMeasurer(it, width)
+        } ?: 0
+        val suffixHeight = measurables.find { it.layoutId == SuffixId }?.let {
+            intrinsicMeasurer(it, width)
+        } ?: 0
         val placeholderHeight = measurables.find { it.layoutId == PlaceholderId }?.let {
             intrinsicMeasurer(it, width)
         } ?: 0
@@ -701,6 +873,8 @@
             labelHeight = labelHeight,
             leadingHeight = leadingHeight,
             trailingHeight = trailingHeight,
+            prefixHeight = prefixHeight,
+            suffixHeight = suffixHeight,
             placeholderHeight = placeholderHeight,
             supportingHeight = supportingHeight,
             isLabelFocused = animationProgress == 1f,
@@ -714,15 +888,19 @@
 private fun calculateWidth(
     leadingWidth: Int,
     trailingWidth: Int,
+    prefixWidth: Int,
+    suffixWidth: Int,
     textFieldWidth: Int,
     labelWidth: Int,
     placeholderWidth: Int,
     constraints: Constraints
 ): Int {
+    val affixTotalWidth = prefixWidth + suffixWidth
     val middleSection = maxOf(
-        textFieldWidth,
+        textFieldWidth + affixTotalWidth,
+        placeholderWidth + affixTotalWidth,
+        // Prefix/suffix does not get applied to label
         labelWidth,
-        placeholderWidth
     )
     val wrappedWidth = leadingWidth + middleSection + trailingWidth
     return max(wrappedWidth, constraints.minWidth)
@@ -733,6 +911,8 @@
     labelHeight: Int,
     leadingHeight: Int,
     trailingHeight: Int,
+    prefixHeight: Int,
+    suffixHeight: Int,
     placeholderHeight: Int,
     supportingHeight: Int,
     isLabelFocused: Boolean,
@@ -759,6 +939,8 @@
         maxOf(
             leadingHeight,
             trailingHeight,
+            prefixHeight,
+            suffixHeight,
             middleSectionHeight.roundToInt()
         ) + supportingHeight
     )
@@ -776,6 +958,8 @@
     placeholderPlaceable: Placeable?,
     leadingPlaceable: Placeable?,
     trailingPlaceable: Placeable?,
+    prefixPlaceable: Placeable?,
+    suffixPlaceable: Placeable?,
     containerPlaceable: Placeable,
     supportingPlaceable: Placeable?,
     singleLine: Boolean,
@@ -814,8 +998,16 @@
         val positionY = startPosition - (distance * animationProgress).roundToInt()
         it.placeRelative(widthOrZero(leadingPlaceable), positionY)
     }
-    textfieldPlaceable.placeRelative(widthOrZero(leadingPlaceable), textPosition)
-    placeholderPlaceable?.placeRelative(widthOrZero(leadingPlaceable), textPosition)
+
+    prefixPlaceable?.placeRelative(widthOrZero(leadingPlaceable), textPosition)
+    suffixPlaceable?.placeRelative(
+        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
+        textPosition,
+    )
+
+    val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
+    textfieldPlaceable.placeRelative(textHorizontalPosition, textPosition)
+    placeholderPlaceable?.placeRelative(textHorizontalPosition, textPosition)
 
     supportingPlaceable?.placeRelative(0, height)
 }
@@ -831,6 +1023,8 @@
     placeholderPlaceable: Placeable?,
     leadingPlaceable: Placeable?,
     trailingPlaceable: Placeable?,
+    prefixPlaceable: Placeable?,
+    suffixPlaceable: Placeable?,
     containerPlaceable: Placeable,
     supportingPlaceable: Placeable?,
     singleLine: Boolean,
@@ -854,25 +1048,35 @@
         Alignment.CenterVertically.align(trailingPlaceable.height, height)
     )
 
-    // Single line text field without label places its input center vertically. Multiline text
-    // field without label places its input at the top with padding
-    val textVerticalPosition = if (singleLine) {
-        Alignment.CenterVertically.align(textPlaceable.height, height)
-    } else {
-        topPadding
-    }
-    textPlaceable.placeRelative(widthOrZero(leadingPlaceable), textVerticalPosition)
-
-    // placeholder is placed similar to the text input above
-    placeholderPlaceable?.let {
-        val placeholderVerticalPosition = if (singleLine) {
-            Alignment.CenterVertically.align(placeholderPlaceable.height, height)
+    // Single line text field without label places its text components centered vertically.
+    // Multiline text field without label places its text components at the top with padding.
+    fun calculateVerticalPosition(placeable: Placeable): Int {
+        return if (singleLine) {
+            Alignment.CenterVertically.align(placeable.height, height)
         } else {
             topPadding
         }
-        it.placeRelative(widthOrZero(leadingPlaceable), placeholderVerticalPosition)
     }
 
+    prefixPlaceable?.placeRelative(
+        widthOrZero(leadingPlaceable),
+        calculateVerticalPosition(prefixPlaceable)
+    )
+
+    suffixPlaceable?.placeRelative(
+        width - widthOrZero(trailingPlaceable) - suffixPlaceable.width,
+        calculateVerticalPosition(suffixPlaceable),
+    )
+
+    val textHorizontalPosition = widthOrZero(leadingPlaceable) + widthOrZero(prefixPlaceable)
+
+    textPlaceable.placeRelative(textHorizontalPosition, calculateVerticalPosition(textPlaceable))
+
+    placeholderPlaceable?.placeRelative(
+        textHorizontalPosition,
+        calculateVerticalPosition(placeholderPlaceable)
+    )
+
     supportingPlaceable?.placeRelative(0, height)
 }
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
index cb61fe6..bc1d6fa 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
@@ -285,6 +285,14 @@
      * disabled
      * @param errorSupportingTextColor the supporting text color for this text field when in error
      * state
+     * @param focusedPrefixColor the prefix color for this text field when focused
+     * @param unfocusedPrefixColor the prefix color for this text field when not focused
+     * @param disabledPrefixColor the prefix color for this text field when disabled
+     * @param errorPrefixColor the prefix color for this text field when in error state
+     * @param focusedSuffixColor the suffix color for this text field when focused
+     * @param unfocusedSuffixColor the suffix color for this text field when not focused
+     * @param disabledSuffixColor the suffix color for this text field when disabled
+     * @param errorSuffixColor the suffix color for this text field when in error state
      */
     @ExperimentalMaterial3Api
     @Composable
@@ -324,6 +332,16 @@
         disabledSupportingTextColor: Color = FilledTextFieldTokens.DisabledSupportingColor.toColor()
             .copy(alpha = FilledTextFieldTokens.DisabledSupportingOpacity),
         errorSupportingTextColor: Color = FilledTextFieldTokens.ErrorSupportingColor.toColor(),
+        focusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.toColor(),
+        unfocusedPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.toColor(),
+        disabledPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.toColor()
+            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
+        errorPrefixColor: Color = FilledTextFieldTokens.InputPrefixColor.toColor(),
+        focusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.toColor(),
+        unfocusedSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.toColor(),
+        disabledSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.toColor()
+            .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
+        errorSuffixColor: Color = FilledTextFieldTokens.InputSuffixColor.toColor(),
     ): TextFieldColors =
         TextFieldColors(
             textColor = textColor,
@@ -354,6 +372,14 @@
             unfocusedSupportingTextColor = unfocusedSupportingTextColor,
             disabledSupportingTextColor = disabledSupportingTextColor,
             errorSupportingTextColor = errorSupportingTextColor,
+            focusedPrefixColor = focusedPrefixColor,
+            unfocusedPrefixColor = unfocusedPrefixColor,
+            disabledPrefixColor = disabledPrefixColor,
+            errorPrefixColor = errorPrefixColor,
+            focusedSuffixColor = focusedSuffixColor,
+            unfocusedSuffixColor = unfocusedSuffixColor,
+            disabledSuffixColor = disabledSuffixColor,
+            errorSuffixColor = errorSuffixColor,
         )
 
     /**
@@ -392,6 +418,14 @@
      * disabled
      * @param errorSupportingTextColor the supporting text color for this text field when in error
      * state
+     * @param focusedPrefixColor the prefix color for this text field when focused
+     * @param unfocusedPrefixColor the prefix color for this text field when not focused
+     * @param disabledPrefixColor the prefix color for this text field when disabled
+     * @param errorPrefixColor the prefix color for this text field when in error state
+     * @param focusedSuffixColor the suffix color for this text field when focused
+     * @param unfocusedSuffixColor the suffix color for this text field when not focused
+     * @param disabledSuffixColor the suffix color for this text field when disabled
+     * @param errorSuffixColor the suffix color for this text field when in error state
      */
     @ExperimentalMaterial3Api
     @Composable
@@ -431,6 +465,16 @@
         disabledSupportingTextColor: Color = OutlinedTextFieldTokens.DisabledSupportingColor
             .toColor().copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
         errorSupportingTextColor: Color = OutlinedTextFieldTokens.ErrorSupportingColor.toColor(),
+        focusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.toColor(),
+        unfocusedPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.toColor(),
+        disabledPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.toColor()
+            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
+        errorPrefixColor: Color = OutlinedTextFieldTokens.InputPrefixColor.toColor(),
+        focusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.toColor(),
+        unfocusedSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.toColor(),
+        disabledSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.toColor()
+            .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
+        errorSuffixColor: Color = OutlinedTextFieldTokens.InputSuffixColor.toColor(),
     ): TextFieldColors =
         TextFieldColors(
             textColor = textColor,
@@ -461,6 +505,14 @@
             unfocusedSupportingTextColor = unfocusedSupportingTextColor,
             disabledSupportingTextColor = disabledSupportingTextColor,
             errorSupportingTextColor = errorSupportingTextColor,
+            focusedPrefixColor = focusedPrefixColor,
+            unfocusedPrefixColor = unfocusedPrefixColor,
+            disabledPrefixColor = disabledPrefixColor,
+            errorPrefixColor = errorPrefixColor,
+            focusedSuffixColor = focusedSuffixColor,
+            unfocusedSuffixColor = unfocusedSuffixColor,
+            disabledSuffixColor = disabledSuffixColor,
+            errorSuffixColor = errorSuffixColor,
         )
 
     /**
@@ -507,7 +559,10 @@
      * field container
      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
      * container
+     * @param prefix the optional prefix to be displayed before the input text in the text field
+     * @param suffix the optional suffix to be displayed after the input text in the text field
      * @param supportingText the optional supporting text to be displayed below the text field
+     * @param shape defines the shape of this text field's container
      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
      * field in different states. See [TextFieldDefaults.textFieldColors].
      * @param contentPadding the spacing values to apply internally between the internals of text
@@ -536,6 +591,8 @@
         placeholder: @Composable (() -> Unit)? = null,
         leadingIcon: @Composable (() -> Unit)? = null,
         trailingIcon: @Composable (() -> Unit)? = null,
+        prefix: @Composable (() -> Unit)? = null,
+        suffix: @Composable (() -> Unit)? = null,
         supportingText: @Composable (() -> Unit)? = null,
         shape: Shape = filledShape,
         colors: TextFieldColors = textFieldColors(),
@@ -558,6 +615,8 @@
             label = label,
             leadingIcon = leadingIcon,
             trailingIcon = trailingIcon,
+            prefix = prefix,
+            suffix = suffix,
             supportingText = supportingText,
             singleLine = singleLine,
             enabled = enabled,
@@ -613,6 +672,8 @@
      * field container
      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
      * container
+     * @param prefix the optional prefix to be displayed before the input text in the text field
+     * @param suffix the optional suffix to be displayed after the input text in the text field
      * @param supportingText the optional supporting text to be displayed below the text field
      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
      * field in different states. See [TextFieldDefaults.outlinedTextFieldColors].
@@ -638,6 +699,8 @@
         placeholder: @Composable (() -> Unit)? = null,
         leadingIcon: @Composable (() -> Unit)? = null,
         trailingIcon: @Composable (() -> Unit)? = null,
+        prefix: @Composable (() -> Unit)? = null,
+        suffix: @Composable (() -> Unit)? = null,
         supportingText: @Composable (() -> Unit)? = null,
         colors: TextFieldColors = outlinedTextFieldColors(),
         contentPadding: PaddingValues = outlinedTextFieldPadding(),
@@ -654,6 +717,8 @@
             label = label,
             leadingIcon = leadingIcon,
             trailingIcon = trailingIcon,
+            prefix = prefix,
+            suffix = suffix,
             supportingText = supportingText,
             singleLine = singleLine,
             enabled = enabled,
@@ -664,6 +729,99 @@
             container = container
         )
     }
+
+    @Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+    @Composable
+    @ExperimentalMaterial3Api
+    fun TextFieldDecorationBox(
+        value: String,
+        innerTextField: @Composable () -> Unit,
+        enabled: Boolean,
+        singleLine: Boolean,
+        visualTransformation: VisualTransformation,
+        interactionSource: InteractionSource,
+        isError: Boolean = false,
+        label: @Composable (() -> Unit)? = null,
+        placeholder: @Composable (() -> Unit)? = null,
+        leadingIcon: @Composable (() -> Unit)? = null,
+        trailingIcon: @Composable (() -> Unit)? = null,
+        supportingText: @Composable (() -> Unit)? = null,
+        shape: Shape = filledShape,
+        colors: TextFieldColors = textFieldColors(),
+        contentPadding: PaddingValues =
+            if (label == null) {
+                textFieldWithoutLabelPadding()
+            } else {
+                textFieldWithLabelPadding()
+            },
+        container: @Composable () -> Unit = {
+            FilledContainerBox(enabled, isError, interactionSource, colors, shape)
+        }
+    ) {
+        TextFieldDecorationBox(
+            value = value,
+            innerTextField = innerTextField,
+            enabled = enabled,
+            singleLine = singleLine,
+            visualTransformation = visualTransformation,
+            interactionSource = interactionSource,
+            isError = isError,
+            label = label,
+            placeholder = placeholder,
+            leadingIcon = leadingIcon,
+            trailingIcon = trailingIcon,
+            prefix = null,
+            suffix = null,
+            supportingText = supportingText,
+            shape = shape,
+            colors = colors,
+            contentPadding = contentPadding,
+            container = container,
+        )
+    }
+
+    @Deprecated("Use overload with prefix and suffix parameters", level = DeprecationLevel.HIDDEN)
+    @Composable
+    @ExperimentalMaterial3Api
+    fun OutlinedTextFieldDecorationBox(
+        value: String,
+        innerTextField: @Composable () -> Unit,
+        enabled: Boolean,
+        singleLine: Boolean,
+        visualTransformation: VisualTransformation,
+        interactionSource: InteractionSource,
+        isError: Boolean = false,
+        label: @Composable (() -> Unit)? = null,
+        placeholder: @Composable (() -> Unit)? = null,
+        leadingIcon: @Composable (() -> Unit)? = null,
+        trailingIcon: @Composable (() -> Unit)? = null,
+        supportingText: @Composable (() -> Unit)? = null,
+        colors: TextFieldColors = outlinedTextFieldColors(),
+        contentPadding: PaddingValues = outlinedTextFieldPadding(),
+        container: @Composable () -> Unit = {
+            OutlinedBorderContainerBox(enabled, isError, interactionSource, colors)
+        }
+    ) {
+        OutlinedTextFieldDecorationBox(
+            value = value,
+            innerTextField = innerTextField,
+            enabled = enabled,
+            singleLine = singleLine,
+            visualTransformation = visualTransformation,
+            interactionSource = interactionSource,
+            isError = isError,
+            label = label,
+            placeholder = placeholder,
+            leadingIcon = leadingIcon,
+            trailingIcon = trailingIcon,
+            prefix = null,
+            suffix = null,
+            supportingText = supportingText,
+            colors = colors,
+            contentPadding = contentPadding,
+            container = container
+        )
+    }
 }
 
 /**
@@ -705,6 +863,14 @@
     private val unfocusedSupportingTextColor: Color,
     private val disabledSupportingTextColor: Color,
     private val errorSupportingTextColor: Color,
+    private val focusedPrefixColor: Color,
+    private val unfocusedPrefixColor: Color,
+    private val disabledPrefixColor: Color,
+    private val errorPrefixColor: Color,
+    private val focusedSuffixColor: Color,
+    private val unfocusedSuffixColor: Color,
+    private val disabledSuffixColor: Color,
+    private val errorSuffixColor: Color,
     ) {
     /**
      * Represents the color used for the leading icon of this text field.
@@ -854,6 +1020,56 @@
     }
 
     /**
+     * Represents the color used for the prefix of this text field.
+     *
+     * @param enabled whether the text field is enabled
+     * @param isError whether the text field's current value is in error
+     * @param interactionSource the [InteractionSource] of this text field. Helps to determine if
+     * the text field is in focus or not
+     */
+    @Composable
+    internal fun prefixColor(
+        enabled: Boolean,
+        isError: Boolean,
+        interactionSource: InteractionSource
+    ): State<Color> {
+        val focused by interactionSource.collectIsFocusedAsState()
+
+        val targetValue = when {
+            !enabled -> disabledPrefixColor
+            isError -> errorPrefixColor
+            focused -> focusedPrefixColor
+            else -> unfocusedPrefixColor
+        }
+        return rememberUpdatedState(targetValue)
+    }
+
+    /**
+     * Represents the color used for the suffix of this text field.
+     *
+     * @param enabled whether the text field is enabled
+     * @param isError whether the text field's current value is in error
+     * @param interactionSource the [InteractionSource] of this text field. Helps to determine if
+     * the text field is in focus or not
+     */
+    @Composable
+    internal fun suffixColor(
+        enabled: Boolean,
+        isError: Boolean,
+        interactionSource: InteractionSource
+    ): State<Color> {
+        val focused by interactionSource.collectIsFocusedAsState()
+
+        val targetValue = when {
+            !enabled -> disabledSuffixColor
+            isError -> errorSuffixColor
+            focused -> focusedSuffixColor
+            else -> unfocusedSuffixColor
+        }
+        return rememberUpdatedState(targetValue)
+    }
+
+    /**
      * Represents the color used for the cursor of this text field.
      *
      * @param isError whether the text field's current value is in error
@@ -901,6 +1117,14 @@
         if (unfocusedSupportingTextColor != other.unfocusedSupportingTextColor) return false
         if (disabledSupportingTextColor != other.disabledSupportingTextColor) return false
         if (errorSupportingTextColor != other.errorSupportingTextColor) return false
+        if (focusedPrefixColor != other.focusedPrefixColor) return false
+        if (unfocusedPrefixColor != other.unfocusedPrefixColor) return false
+        if (disabledPrefixColor != other.disabledPrefixColor) return false
+        if (errorPrefixColor != other.errorPrefixColor) return false
+        if (focusedSuffixColor != other.focusedSuffixColor) return false
+        if (unfocusedSuffixColor != other.unfocusedSuffixColor) return false
+        if (disabledSuffixColor != other.disabledSuffixColor) return false
+        if (errorSuffixColor != other.errorSuffixColor) return false
 
         return true
     }
@@ -934,6 +1158,14 @@
         result = 31 * result + unfocusedSupportingTextColor.hashCode()
         result = 31 * result + disabledSupportingTextColor.hashCode()
         result = 31 * result + errorSupportingTextColor.hashCode()
+        result = 31 * result + focusedPrefixColor.hashCode()
+        result = 31 * result + unfocusedPrefixColor.hashCode()
+        result = 31 * result + disabledPrefixColor.hashCode()
+        result = 31 * result + errorPrefixColor.hashCode()
+        result = 31 * result + focusedSuffixColor.hashCode()
+        result = 31 * result + unfocusedSuffixColor.hashCode()
+        result = 31 * result + disabledSuffixColor.hashCode()
+        result = 31 * result + errorSuffixColor.hashCode()
         return result
     }
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
index b7b633b..51f7f04 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldImpl.kt
@@ -69,6 +69,8 @@
     placeholder: @Composable (() -> Unit)? = null,
     leadingIcon: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
+    prefix: @Composable (() -> Unit)? = null,
+    suffix: @Composable (() -> Unit)? = null,
     supportingText: @Composable (() -> Unit)? = null,
     singleLine: Boolean = false,
     enabled: Boolean = true,
@@ -110,7 +112,8 @@
         },
         contentColor = labelColor,
         showLabel = label != null
-    ) { labelProgress, labelTextStyleColor, labelContentColor, placeholderAlphaProgress ->
+    ) { labelProgress, labelTextStyleColor, labelContentColor, placeholderAlphaProgress,
+        prefixSuffixAlphaProgress ->
 
         val decoratedLabel: @Composable (() -> Unit)? = label?.let {
             @Composable {
@@ -138,6 +141,24 @@
                 }
             } else null
 
+        val prefixColor = colors.prefixColor(enabled, isError, interactionSource).value
+        val decoratedPrefix: @Composable (() -> Unit)? = prefix?.let {
+            @Composable {
+                Box(Modifier.alpha(prefixSuffixAlphaProgress)) {
+                    Decoration(contentColor = prefixColor, typography = bodyLarge, content = it)
+                }
+            }
+        }
+
+        val suffixColor = colors.suffixColor(enabled, isError, interactionSource).value
+        val decoratedSuffix: @Composable (() -> Unit)? = suffix?.let {
+            @Composable {
+                Box(Modifier.alpha(prefixSuffixAlphaProgress)) {
+                    Decoration(contentColor = suffixColor, typography = bodyLarge, content = it)
+                }
+            }
+        }
+
         // Developers need to handle invalid input manually. But since we don't provide error
         // message slot API, we can set the default error message in case developers forget about
         // it.
@@ -182,6 +203,8 @@
                     label = decoratedLabel,
                     leading = decoratedLeading,
                     trailing = decoratedTrailing,
+                    prefix = decoratedPrefix,
+                    suffix = decoratedSuffix,
                     container = containerWithId,
                     supporting = decoratedSupporting,
                     singleLine = singleLine,
@@ -210,6 +233,8 @@
                     label = decoratedLabel,
                     leading = decoratedLeading,
                     trailing = decoratedTrailing,
+                    prefix = decoratedPrefix,
+                    suffix = decoratedSuffix,
                     supporting = decoratedSupporting,
                     singleLine = singleLine,
                     onLabelMeasured = {
@@ -263,7 +288,8 @@
             labelProgress: Float,
             labelTextStyleColor: Color,
             labelContentColor: Color,
-            placeholderOpacity: Float
+            placeholderOpacity: Float,
+            prefixSuffixOpacity: Float,
         ) -> Unit
     ) {
         // Transitions from/to InputPhase.Focused are the most critical in the transition below.
@@ -310,6 +336,17 @@
             }
         }
 
+        val prefixSuffixOpacity by transition.animateFloat(
+            label = "PrefixSuffixOpacity",
+            transitionSpec = { tween(durationMillis = AnimationDuration) }
+        ) {
+            when (it) {
+                InputPhase.Focused -> 1f
+                InputPhase.UnfocusedEmpty -> if (showLabel) 0f else 1f
+                InputPhase.UnfocusedNotEmpty -> 1f
+            }
+        }
+
         val labelTextStyleColor by transition.animateColor(
             transitionSpec = { tween(durationMillis = AnimationDuration) },
             label = "LabelTextStyleColor"
@@ -330,7 +367,8 @@
             labelProgress,
             labelTextStyleColor,
             labelContentColor,
-            placeholderOpacity
+            placeholderOpacity,
+            prefixSuffixOpacity,
         )
     }
 }
@@ -357,6 +395,8 @@
 internal const val LabelId = "Label"
 internal const val LeadingId = "Leading"
 internal const val TrailingId = "Trailing"
+internal const val PrefixId = "Prefix"
+internal const val SuffixId = "Suffix"
 internal const val SupportingId = "Supporting"
 internal const val ContainerId = "Container"
 internal val ZeroConstraints = Constraints(0, 0, 0, 0)
@@ -368,5 +408,6 @@
 internal val TextFieldPadding = 16.dp
 internal val HorizontalIconPadding = 12.dp
 internal val SupportingTopPadding = 4.dp
+internal val PrefixSuffixTextPadding = 2.dp
 
 internal val IconDefaultSizeModifier = Modifier.defaultMinSize(48.dp, 48.dp)
\ No newline at end of file
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index d2dd899..8fc4fc2 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -1368,9 +1368,9 @@
     property public final int None;
   }
 
-  @androidx.compose.runtime.Immutable public final class LineBreak {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class LineBreak {
     ctor public LineBreak(int strategy, int strictness, int wordBreak);
-    method public androidx.compose.ui.text.style.LineBreak copy(optional int strategy, optional int strictness, optional int wordBreak);
+    method public int copy(optional int strategy, optional int strictness, optional int wordBreak);
     method public int getStrategy();
     method public int getStrictness();
     method public int getWordBreak();
@@ -1381,12 +1381,12 @@
   }
 
   public static final class LineBreak.Companion {
-    method public androidx.compose.ui.text.style.LineBreak getHeading();
-    method public androidx.compose.ui.text.style.LineBreak getParagraph();
-    method public androidx.compose.ui.text.style.LineBreak getSimple();
-    property public final androidx.compose.ui.text.style.LineBreak Heading;
-    property public final androidx.compose.ui.text.style.LineBreak Paragraph;
-    property public final androidx.compose.ui.text.style.LineBreak Simple;
+    method public int getHeading();
+    method public int getParagraph();
+    method public int getSimple();
+    property public final int Heading;
+    property public final int Paragraph;
+    property public final int Simple;
   }
 
   @kotlin.jvm.JvmInline public static final value class LineBreak.Strategy {
@@ -1428,6 +1428,9 @@
     property public final int Phrase;
   }
 
+  public final class LineBreak_androidKt {
+  }
+
   public final class LineHeightStyle {
     ctor public LineHeightStyle(float alignment, int trim);
     method public float getAlignment();
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index c3c178e..a2274b7 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -1436,9 +1436,9 @@
     property public final int None;
   }
 
-  @androidx.compose.runtime.Immutable public final class LineBreak {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class LineBreak {
     ctor public LineBreak(int strategy, int strictness, int wordBreak);
-    method public androidx.compose.ui.text.style.LineBreak copy(optional int strategy, optional int strictness, optional int wordBreak);
+    method public int copy(optional int strategy, optional int strictness, optional int wordBreak);
     method public int getStrategy();
     method public int getStrictness();
     method public int getWordBreak();
@@ -1449,12 +1449,12 @@
   }
 
   public static final class LineBreak.Companion {
-    method public androidx.compose.ui.text.style.LineBreak getHeading();
-    method public androidx.compose.ui.text.style.LineBreak getParagraph();
-    method public androidx.compose.ui.text.style.LineBreak getSimple();
-    property public final androidx.compose.ui.text.style.LineBreak Heading;
-    property public final androidx.compose.ui.text.style.LineBreak Paragraph;
-    property public final androidx.compose.ui.text.style.LineBreak Simple;
+    method public int getHeading();
+    method public int getParagraph();
+    method public int getSimple();
+    property public final int Heading;
+    property public final int Paragraph;
+    property public final int Simple;
   }
 
   @kotlin.jvm.JvmInline public static final value class LineBreak.Strategy {
@@ -1496,6 +1496,9 @@
     property public final int Phrase;
   }
 
+  public final class LineBreak_androidKt {
+  }
+
   public final class LineHeightStyle {
     ctor public LineHeightStyle(float alignment, int trim);
     method public float getAlignment();
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index d2dd899..8fc4fc2 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -1368,9 +1368,9 @@
     property public final int None;
   }
 
-  @androidx.compose.runtime.Immutable public final class LineBreak {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class LineBreak {
     ctor public LineBreak(int strategy, int strictness, int wordBreak);
-    method public androidx.compose.ui.text.style.LineBreak copy(optional int strategy, optional int strictness, optional int wordBreak);
+    method public int copy(optional int strategy, optional int strictness, optional int wordBreak);
     method public int getStrategy();
     method public int getStrictness();
     method public int getWordBreak();
@@ -1381,12 +1381,12 @@
   }
 
   public static final class LineBreak.Companion {
-    method public androidx.compose.ui.text.style.LineBreak getHeading();
-    method public androidx.compose.ui.text.style.LineBreak getParagraph();
-    method public androidx.compose.ui.text.style.LineBreak getSimple();
-    property public final androidx.compose.ui.text.style.LineBreak Heading;
-    property public final androidx.compose.ui.text.style.LineBreak Paragraph;
-    property public final androidx.compose.ui.text.style.LineBreak Simple;
+    method public int getHeading();
+    method public int getParagraph();
+    method public int getSimple();
+    property public final int Heading;
+    property public final int Paragraph;
+    property public final int Simple;
   }
 
   @kotlin.jvm.JvmInline public static final value class LineBreak.Strategy {
@@ -1428,6 +1428,9 @@
     property public final int Phrase;
   }
 
+  public final class LineBreak_androidKt {
+  }
+
   public final class LineHeightStyle {
     ctor public LineHeightStyle(float alignment, int trim);
     method public float getAlignment();
diff --git a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt
index 7183f6c..d7d0b85 100644
--- a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt
+++ b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/HyphensLineBreakBenchmark.kt
@@ -39,8 +39,8 @@
 @OptIn(ExperimentalTextApi::class, InternalPlatformTextApi::class)
 class HyphensLineBreakBenchmark(
     private val textLength: Int,
-    private val hyphensWrapper: HyphensWrapper,
-    private val lineBreak: LineBreak
+    private val hyphensString: String,
+    private val lineBreakString: String
 ) {
     companion object {
         @JvmStatic
@@ -48,8 +48,15 @@
         fun initParameters(): List<Array<Any?>> {
             return cartesian(
                 arrayOf(32, 128, 512),
-                arrayOf(Hyphens.None.wrap, Hyphens.Auto.wrap),
-                arrayOf(LineBreak.Paragraph, LineBreak.Simple, LineBreak.Heading)
+                arrayOf(
+                    Hyphens.None.toTestString(),
+                    Hyphens.Auto.toTestString()
+                ),
+                arrayOf(
+                    LineBreak.Paragraph.toTestString(),
+                    LineBreak.Simple.toTestString(),
+                    LineBreak.Heading.toTestString()
+                )
             )
         }
     }
@@ -62,10 +69,11 @@
 
     private val width = 100
     private val textSize: Float = 10F
-    private val hyphenationFrequency = toLayoutHyphenationFrequency(hyphensWrapper.hyphens)
-    private val lineBreakStyle = toLayoutLineBreakStyle(lineBreak.strictness)
-    private val breakStrategy = toLayoutBreakStrategy(lineBreak.strategy)
-    private val lineBreakWordStyle = toLayoutLineBreakWordStyle(lineBreak.wordBreak)
+    private val hyphenationFrequency = toLayoutHyphenationFrequency(hyphensString.toHyphens())
+    private val lineBreakStyle = toLayoutLineBreakStyle(lineBreakString.toLineBreak().strictness)
+    private val breakStrategy = toLayoutBreakStrategy(lineBreakString.toLineBreak().strategy)
+    private val lineBreakWordStyle =
+        toLayoutLineBreakWordStyle(lineBreakString.toLineBreak().wordBreak)
 
     @Test
     fun constructLayout() {
@@ -143,8 +151,35 @@
 /**
  * Required to make this test work due to a bug with value classes and Parameterized JUnit tests.
  * https://youtrack.jetbrains.com/issue/KT-35523
+ *
+ * However, it's not enough to use a wrapper because wrapper makes the test name unnecessarily
+ * long which causes Perfetto to be unable to create output files with a very long name in some
+ * file systems.
+ *
+ * Using a String instead of an Integer gives us a better test naming.
  */
-data class HyphensWrapper(val hyphens: Hyphens)
+private fun String.toLineBreak(): LineBreak = when (this) {
+    "Simple" -> LineBreak.Simple
+    "Heading" -> LineBreak.Heading
+    "Paragraph" -> LineBreak.Paragraph
+    else -> throw IllegalArgumentException("Unrecognized LineBreak value for this test")
+}
 
-val Hyphens.wrap: HyphensWrapper
-    get() = HyphensWrapper(this)
\ No newline at end of file
+private fun LineBreak.toTestString(): String = when (this) {
+    LineBreak.Simple -> "Simple"
+    LineBreak.Heading -> "Heading"
+    LineBreak.Paragraph -> "Paragraph"
+    else -> throw IllegalArgumentException("Unrecognized LineBreak value for this test")
+}
+
+private fun String.toHyphens(): Hyphens = when (this) {
+    "None" -> Hyphens.None
+    "Auto" -> Hyphens.Auto
+    else -> throw IllegalArgumentException("Unrecognized Hyphens value for this test")
+}
+
+private fun Hyphens.toTestString(): String = when (this) {
+    Hyphens.None -> "None"
+    Hyphens.Auto -> "Auto"
+    else -> throw IllegalArgumentException("Unrecognized Hyphens value for this test")
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
index 69d112c..d8f528f 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/style/LineBreakTest.kt
@@ -16,14 +16,12 @@
 
 package androidx.compose.ui.text.style
 
-import androidx.compose.ui.text.ExperimentalTextApi
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@OptIn(ExperimentalTextApi::class)
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class LineBreakTest : TextLineBreaker() {
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/style/LineBreak.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/style/LineBreak.android.kt
index e5d7061..cdd2a88 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/style/LineBreak.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/style/LineBreak.android.kt
@@ -37,17 +37,53 @@
  *
  * @sample androidx.compose.ui.text.samples.LineBreakSample
  * @sample androidx.compose.ui.text.samples.AndroidLineBreakSample
- *
- * @param strategy defines the algorithm that inserts line breaks
- * @param strictness defines the line breaking rules
- * @param wordBreak defines how words are broken
  */
 @Immutable
-actual class LineBreak(
-    val strategy: Strategy,
-    val strictness: Strictness,
-    val wordBreak: WordBreak
+@JvmInline
+actual value class LineBreak private constructor(
+    internal val mask: Int
 ) {
+
+    /**
+     * This represents a configuration for line breaking on Android, describing [Strategy],
+     * [Strictness], and [WordBreak].
+     *
+     * @param strategy defines the algorithm that inserts line breaks
+     * @param strictness defines the line breaking rules
+     * @param wordBreak defines how words are broken
+     */
+    constructor(
+        strategy: Strategy,
+        strictness: Strictness,
+        wordBreak: WordBreak
+    ) : this(packBytes(
+        strategy.value,
+        strictness.value,
+        wordBreak.value
+    ))
+
+    val strategy: Strategy
+        get() = Strategy(unpackByte1(mask))
+
+    val strictness: Strictness
+        get() = Strictness(unpackByte2(mask))
+
+    val wordBreak: WordBreak
+        get() = WordBreak(unpackByte3(mask))
+
+    fun copy(
+        strategy: Strategy = this.strategy,
+        strictness: Strictness = this.strictness,
+        wordBreak: WordBreak = this.wordBreak
+    ): LineBreak = LineBreak(
+        strategy = strategy,
+        strictness = strictness,
+        wordBreak = wordBreak
+    )
+
+    override fun toString(): String =
+        "LineBreak(strategy=$strategy, strictness=$strictness, wordBreak=$wordBreak)"
+
     actual companion object {
         /**
          * The greedy, fast line breaking algorithm. Ideal for text that updates often,
@@ -122,42 +158,11 @@
         )
     }
 
-    fun copy(
-        strategy: Strategy = this.strategy,
-        strictness: Strictness = this.strictness,
-        wordBreak: WordBreak = this.wordBreak
-    ): LineBreak = LineBreak(
-        strategy = strategy,
-        strictness = strictness,
-        wordBreak = wordBreak
-    )
-
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is LineBreak) return false
-
-        if (strategy != other.strategy) return false
-        if (strictness != other.strictness) return false
-        if (wordBreak != other.wordBreak) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = strategy.hashCode()
-        result = 31 * result + strictness.hashCode()
-        result = 31 * result + wordBreak.hashCode()
-        return result
-    }
-
-    override fun toString(): String =
-        "LineBreak(strategy=$strategy, strictness=$strictness, wordBreak=$wordBreak)"
-
     /**
      * The strategy used for line breaking.
      */
     @JvmInline
-    value class Strategy private constructor(private val value: Int) {
+    value class Strategy internal constructor(internal val value: Int) {
         companion object {
             /**
              * Basic, fast break strategy. Hyphenation, if enabled, is done only for words
@@ -216,7 +221,7 @@
      * line breaks can be inserted. It is useful when working with CJK scripts.
      */
     @JvmInline
-    value class Strictness private constructor(private val value: Int) {
+    value class Strictness internal constructor(internal val value: Int) {
         companion object {
             /**
              * Default breaking rules for the locale, which may correspond to [Normal] or [Strict].
@@ -260,7 +265,7 @@
      * Describes how line breaks should be inserted within words.
      */
     @JvmInline
-    value class WordBreak private constructor(private val value: Int) {
+    value class WordBreak internal constructor(internal val value: Int) {
         companion object {
             /**
              * Default word breaking rules for the locale.
@@ -313,4 +318,22 @@
             else -> "Invalid"
         }
     }
-}
\ No newline at end of file
+}
+
+/**
+ * Packs 3 bytes represented as Integers into a single Integer.
+ *
+ * A byte can represent any value between 0 and 256.
+ *
+ * Only the 8 least significant bits of any given value are packed into the returned Integer.
+ *
+ */
+private fun packBytes(i1: Int, i2: Int, i3: Int): Int {
+    return i1 or (i2 shl 8) or (i3 shl 16)
+}
+
+private fun unpackByte1(mask: Int) = 0x000000FF and mask
+
+private fun unpackByte2(mask: Int) = 0x000000FF and (mask shr 8)
+
+private fun unpackByte3(mask: Int) = 0x000000FF and (mask shr 16)
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/style/LineBreak.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/style/LineBreak.kt
index d25b7e7..44d49c1 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/style/LineBreak.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/style/LineBreak.kt
@@ -17,6 +17,7 @@
 package androidx.compose.ui.text.style
 
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
 import androidx.compose.ui.text.style.LineBreak.Companion.Heading
 import androidx.compose.ui.text.style.LineBreak.Companion.Paragraph
 import androidx.compose.ui.text.style.LineBreak.Companion.Simple
@@ -41,24 +42,29 @@
  * @sample androidx.compose.ui.text.samples.AndroidLineBreakSample
  */
 @Immutable
-expect class LineBreak {
+expect value class LineBreak private constructor(
+    private val mask: Int
+) {
     companion object {
         /**
          * Basic, fast line breaking. Ideal for text input fields, as it will cause minimal
          * text reflow when editing.
          */
+        @Stable
         val Simple: LineBreak
 
         /**
          * Looser breaking rules, suitable for short text such as titles or narrow newspaper
          * columns. For longer lines of text, use [Paragraph] for improved readability.
          */
+        @Stable
         val Heading: LineBreak
 
         /**
          * Slower, higher quality line breaking for improved readability.
          * Suitable for larger amounts of text.
          */
+        @Stable
         val Paragraph: LineBreak
     }
 }
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/style/LineBreak.skiko.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/style/LineBreak.skiko.kt
index f611ea1..300119a 100644
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/style/LineBreak.skiko.kt
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/style/LineBreak.skiko.kt
@@ -19,12 +19,15 @@
 import androidx.compose.runtime.Immutable
 
 @Immutable
-actual class LineBreak private constructor() {
+@JvmInline
+actual value class LineBreak private constructor(
+    internal val mask: Int
+) {
     actual companion object {
-        actual val Simple: LineBreak = LineBreak()
+        actual val Simple: LineBreak = LineBreak(1)
 
-        actual val Heading: LineBreak = LineBreak()
+        actual val Heading: LineBreak = LineBreak(2)
 
-        actual val Paragraph: LineBreak = LineBreak()
+        actual val Paragraph: LineBreak = LineBreak(3)
     }
 }
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/InputModeTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/InputModeTest.kt
index 9a5fc62..a6c1663 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/InputModeTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/InputModeTest.kt
@@ -16,25 +16,24 @@
 
 package androidx.compose.ui.input
 
-import android.os.Build
+import android.os.Build.VERSION.SDK_INT
 import android.view.View
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.setFocusableContent
-import androidx.compose.ui.input.InputMode.Companion.Touch
 import androidx.compose.ui.input.InputMode.Companion.Keyboard
+import androidx.compose.ui.input.InputMode.Companion.Touch
 import androidx.compose.ui.platform.LocalInputModeManager
-import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
 import androidx.test.filters.FlakyTest
+import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
+import org.junit.After
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -50,17 +49,14 @@
     private lateinit var inputModeManager: InputModeManager
     private lateinit var view: View
 
-    init {
-        InstrumentationRegistry.getInstrumentation().setInTouchMode(param.inputMode == Touch)
+    // TODO(b/267253920): Add a compose test API to set/reset InputMode.
+    @After
+    fun resetTouchMode() = with(InstrumentationRegistry.getInstrumentation()) {
+        if (SDK_INT < 33) setInTouchMode(true) else resetInTouchMode()
     }
 
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun initialInputMode() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
         // Arrange.
         rule.setContentWithInputManager {
             Box {}
@@ -71,19 +67,14 @@
     }
 
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun switchToTouchModeProgrammatically() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
         // Arrange.
         rule.setContentWithInputManager {
             Box {}
         }
 
         // Act.
-        val requestGranted = rule.runOnUiThread {
+        val requestGranted = rule.runOnIdle {
             inputModeManager.requestInputMode(Touch)
         }
 
@@ -104,12 +95,7 @@
 
     @FlakyTest(bugId = 202524920)
     @Test
-    @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
     fun switchToKeyboardModeProgrammatically() {
-        if (Build.VERSION.SDK_INT == 33 && Build.VERSION.CODENAME != "REL") {
-            return // b/262909049: Do not run this test on pre-release Android U.
-        }
-
         // Arrange.
         val testTag = "Box"
         rule.setContentWithInputManager {
@@ -117,23 +103,23 @@
         }
 
         // Act.
-        val requestGranted = rule.runOnUiThread {
+        val requestGranted = rule.runOnIdle {
             inputModeManager.requestInputMode(Keyboard)
         }
 
         // Assert
         rule.runOnIdle { assertThat(requestGranted).isTrue() }
-        rule.waitUntil { inputModeManager.inputMode == Keyboard }
+        assertThat(inputModeManager.inputMode).isEqualTo(Keyboard)
     }
 
     private fun ComposeContentTestRule.setContentWithInputManager(
         composable: @Composable () -> Unit
     ) {
-        this.setFocusableContent {
+        setFocusableContent {
             inputModeManager = LocalInputModeManager.current
-            view = LocalView.current
             composable()
         }
+        runOnIdle { inputModeManager.requestInputMode(param.inputMode) }
     }
 
     // We need to wrap the inline class parameter in another class because Java can't instantiate
@@ -147,4 +133,4 @@
         @Parameterized.Parameters(name = "initialInputMode = {0}")
         fun initParameters() = listOf(Param(Touch), Param(Keyboard))
     }
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index e8c3bc2..be43b17 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -1159,6 +1159,9 @@
             onViewTreeOwnersAvailable?.invoke(viewTreeOwners)
             onViewTreeOwnersAvailable = null
         }
+
+        _inputModeManager.inputMode = if (isInTouchMode) Touch else Keyboard
+
         viewTreeOwners!!.lifecycleOwner.lifecycle.addObserver(this)
         viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
         viewTreeObserver.addOnScrollChangedListener(scrollChangedListener)
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
index 2b9f6b6..8982ac3 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
@@ -25,6 +25,7 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.graphics.Color
+import android.graphics.Rect
 import android.os.Bundle
 import android.os.LocaleList
 import android.util.Log
@@ -100,7 +101,6 @@
         val context = this.createConfigurationContext(config)
 
         val hostView = host.createView(context, appWidgetId, info) as TestAppWidgetHostView
-        hostView.setPadding(0, 0, 0, 0)
         val contentFrame = findViewById<FrameLayout>(R.id.content)
         contentFrame.addView(hostView)
         hostView.setSizes(portraitSize, landscapeSize)
@@ -213,7 +213,18 @@
         val displayMetrics = resources.displayMetrics
         val width = size.width.toPixels(displayMetrics)
         val height = size.height.toPixels(displayMetrics)
-        layoutParams = LayoutParams(width, height, Gravity.CENTER)
+
+        // The widget host applies a default padding that is difficult to remove. Make the outer
+        // host view bigger by the default padding amount, so that the inner view that we care about
+        // matches the provided size.
+        val hostViewPadding = Rect()
+        val testComponent =
+            ComponentName(context.applicationContext, TestGlanceAppWidgetReceiver::class.java)
+        getDefaultPaddingForWidget(context, testComponent, hostViewPadding)
+        val paddedWidth = width + hostViewPadding.left + hostViewPadding.right
+        val paddedHeight = height + hostViewPadding.top + hostViewPadding.bottom
+
+        layoutParams = LayoutParams(paddedWidth, paddedHeight, Gravity.CENTER)
         requestLayout()
     }
 
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
index ac37082..702b60f 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
@@ -35,10 +35,8 @@
 import android.widget.TextView
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpSize
@@ -110,7 +108,6 @@
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertThrows
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -228,7 +225,6 @@
         }
     }
 
-    @Ignore("b/266588723")
     @Test
     fun createTextWithFillMaxDimensions() {
         TestGlanceAppWidget.uiDefinition = {
@@ -347,7 +343,6 @@
         }
     }
 
-    @Ignore("b/265078768")
     @Test
     fun createRowWithTwoTexts() {
         TestGlanceAppWidget.uiDefinition = {
@@ -365,6 +360,7 @@
             val children = row.notGoneChildren.toList()
             val child1 = children[0].getTargetView<TextView>()
             val child2 = assertIs<TextView>(children[1])
+
             assertViewSize(child1, DpSize(mHostRule.portraitSize.width / 2, 100.dp))
             assertViewSize(
                 child2,
@@ -399,7 +395,10 @@
     }
 
     @Test
-    fun createColumnWithTwoTexts2() {
+    fun columnWithWeightedItemRespectsSizeOfOtherItem() {
+        // When one item has a default weight, it should scale to respect the size of the other item
+        // in this case the other item fills the column, so the weighted item should take up no
+        // space, that is, has height 0.
         TestGlanceAppWidget.uiDefinition = {
             Column(modifier = GlanceModifier.fillMaxWidth().fillMaxHeight()) {
                 Text("Inside 1", modifier = GlanceModifier.fillMaxWidth().defaultWeight())
@@ -767,7 +766,6 @@
         }
     }
 
-    @Ignore // b/259718271
     @Test
     fun compoundButtonAction() {
         val checkbox = "checkbox"
@@ -1105,9 +1103,11 @@
 
     private fun assertViewSize(view: View, expectedSize: DpSize) {
         val density = view.context.resources.displayMetrics.density
-        assertThat(view.width / density).isWithin(1.1f / density)
+        assertWithMessage("${view.accessibilityClassName} width").that(view.width / density)
+            .isWithin(1.1f / density)
             .of(expectedSize.width.value)
-        assertThat(view.height / density).isWithin(1.1f / density)
+        assertWithMessage("${view.accessibilityClassName} height").that(view.height / density)
+            .isWithin(1.1f / density)
             .of(expectedSize.height.value)
     }
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 81d8218..96698fc 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -366,6 +366,16 @@
         ): KspTypeElement {
             return when (ksClassDeclaration.classKind) {
                 ClassKind.ENUM_CLASS -> KspEnumTypeElement(env, ksClassDeclaration)
+                ClassKind.ENUM_ENTRY -> {
+                    val enclosingEnumTypeElement =
+                        create(env, ksClassDeclaration.parentDeclaration as KSClassDeclaration)
+                    check(enclosingEnumTypeElement is KspEnumTypeElement) {
+                        "Internal error. The parent declaration of $ksClassDeclaration should " +
+                            "have been wrapped in a KspEnumTypeElement but was " +
+                            enclosingEnumTypeElement::class
+                    }
+                    KspEnumEntry(env, ksClassDeclaration, enclosingEnumTypeElement)
+                }
                 else -> DefaultKspTypeElement(env, ksClassDeclaration)
             }
         }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index da53f87..e44db5b 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -1510,6 +1510,12 @@
                 assertWithMessage("$qName  does not report enum constants in declared fields")
                     .that(typeElement.getDeclaredFields().map { it.name })
                     .containsExactly("x")
+                typeElement.getEnclosedElements().let { elements ->
+                    assertThat(elements.filter { it.name == "VAL1" }.all { it is XEnumEntry })
+                        .isTrue()
+                    assertThat(elements.filter { it.name == "VAL2" }.all { it is XEnumEntry })
+                        .isTrue()
+                }
             }
         }
     }
diff --git a/samples/MediaRoutingDemo/src/main/AndroidManifest.xml b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
index 0c06dfa..bc93b71 100644
--- a/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
+++ b/samples/MediaRoutingDemo/src/main/AndroidManifest.xml
@@ -25,7 +25,7 @@
     <application
         android:hardwareAccelerated="true"
         android:icon="@drawable/app_sample_code"
-        android:label="@string/activity_sample_code"
+        android:label="@string/media_router_app_name"
         android:supportsRtl="true"
         android:theme="@style/Theme.SampleMediaRouter">
 
@@ -33,7 +33,7 @@
             android:name=".activities.MainActivity"
             android:configChanges="orientation|screenSize"
             android:exported="true"
-            android:label="@string/sample_media_router_activity_dark">
+            android:label="@string/main_activity_label">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.androidx.SAMPLE_CODE" />
@@ -46,7 +46,7 @@
             android:name=".activities.SettingsActivity"
             android:configChanges="orientation|screenSize"
             android:exported="true"
-            android:label="@string/sample_media_router_activity_dark">
+            android:label="@string/settings_activity_label">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
@@ -56,7 +56,7 @@
             android:name=".activities.AddEditRouteActivity"
             android:configChanges="orientation|screenSize"
             android:exported="false"
-            android:label="@string/sample_media_router_activity_dark">
+            android:label="@string/add_edit_route_activity_label">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.androidx.SAMPLE_CODE" />
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/AddEditRouteActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/AddEditRouteActivity.java
index 6b2b256..7741f9f 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/AddEditRouteActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/AddEditRouteActivity.java
@@ -43,7 +43,6 @@
 
 /** Allows the user to add and edit routes. */
 public class AddEditRouteActivity extends AppCompatActivity {
-
     private static final String EXTRA_ROUTE_ID_KEY = "routeId";
 
     private SampleDynamicGroupMediaRouteProviderService mService;
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/MainActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/MainActivity.java
index 6133c5e..86feee7 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/MainActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/MainActivity.java
@@ -91,18 +91,7 @@
     private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 5001;
     private static final boolean ENABLE_DEFAULT_CONTROL_CHECK_BOX = false;
 
-    private MediaRouter mMediaRouter;
-    private RoutesManager mRoutesManager;
-    private MediaRouteSelector mSelector;
-    private PlaylistAdapter mPlayListItems;
-    private TextView mInfoTextView;
-    private ListView mPlayListView;
-    CheckBox mUseDefaultControlCheckBox;
-    private ImageButton mPauseResumeButton;
-    private SeekBar mSeekBar;
-
-    final Handler mHandler = new Handler();
-
+    private final Handler mHandler = new Handler();
     private final Runnable mUpdateSeekRunnable =
             new Runnable() {
                 @Override
@@ -112,10 +101,7 @@
                     mHandler.postDelayed(this, 1000);
                 }
             };
-
-    final SessionManager mSessionManager = new SessionManager("app");
-    Player mPlayer;
-
+    private final SessionManager mSessionManager = new SessionManager("app");
     private final MediaRouter.OnPrepareTransferListener mOnPrepareTransferListener =
             (fromRoute, toRoute) -> {
                 Log.d(TAG, "onPrepareTransfer: from=" + fromRoute.getId()
@@ -125,7 +111,6 @@
                     return "onPrepareTransfer";
                 });
             };
-
     private final MediaRouter.Callback mMediaRouterCB = new MediaRouter.Callback() {
         // Return a custom callback that will simply log all of the route events
         // for demonstration purposes.
@@ -216,7 +201,16 @@
         }
     };
 
-    MediaSessionCompat mMediaSession;
+    private MediaRouter mMediaRouter;
+    private MediaRouteSelector mSelector;
+    private PlaylistAdapter mPlayListItems;
+    private TextView mInfoTextView;
+    private ListView mPlayListView;
+    private CheckBox mUseDefaultControlCheckBox;
+    private ImageButton mPauseResumeButton;
+    private SeekBar mSeekBar;
+    private Player mPlayer;
+    private MediaSessionCompat mMediaSession;
     private ComponentName mEventReceiver;
     private PendingIntent mMediaPendingIntent;
 
@@ -229,8 +223,8 @@
         mMediaRouter = MediaRouter.getInstance(this);
         mMediaRouter.setRouterParams(getRouterParams());
 
-        mRoutesManager = RoutesManager.getInstance(getApplicationContext());
-        mRoutesManager.reloadDialogType();
+        RoutesManager routesManager = RoutesManager.getInstance(getApplicationContext());
+        routesManager.reloadDialogType();
 
         // Create a route selector for the type of routes that we care about.
         mSelector = new MediaRouteSelector.Builder()
@@ -399,6 +393,61 @@
         updateUi();
     }
 
+    @Override
+    protected void onDestroy() {
+        mSessionManager.stop();
+        mPlayer.release();
+        mMediaSession.release();
+        mMediaRouter.removeCallback(mMediaRouterCB);
+        super.onDestroy();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(@NonNull Menu menu) {
+        // Be sure to call the super class.
+        super.onCreateOptionsMenu(menu);
+
+        // Inflate the menu and configure the media router action provider.
+        getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
+
+        MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
+        MediaRouteActionProvider mediaRouteActionProvider =
+                (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
+        if (mediaRouteActionProvider != null) {
+            mediaRouteActionProvider.setRouteSelector(mSelector);
+            mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
+                @NonNull
+                @Override
+                public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
+                    return new ControllerDialogFragment(MainActivity.this,
+                            mUseDefaultControlCheckBox);
+                }
+            });
+        }
+
+        // Return true to show the menu.
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+        if (item.getItemId() == R.id.settings_menu_item) {
+            startActivity(new Intent(this, SettingsActivity.class));
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, @Nullable KeyEvent event) {
+        return handleMediaKey(event) || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, @Nullable KeyEvent event) {
+        return handleMediaKey(event) || super.onKeyUp(keyCode, event);
+    }
+
     private void requestRequiredPermissions() {
         requestDisplayOverOtherAppsPermission();
         requestPostNotificationsPermission();
@@ -464,7 +513,7 @@
     /**
      * Handle media key events.
      */
-    public boolean handleMediaKey(@Nullable KeyEvent event) {
+    private boolean handleMediaKey(@Nullable KeyEvent event) {
         if (event != null && event.getAction() == KeyEvent.ACTION_DOWN
                 && event.getRepeatCount() == 0) {
             switch (event.getKeyCode()) {
@@ -504,74 +553,13 @@
         return false;
     }
 
-    @Override
-    public boolean onKeyDown(int keyCode, @Nullable KeyEvent event) {
-        return handleMediaKey(event) || super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, @Nullable KeyEvent event) {
-        return handleMediaKey(event) || super.onKeyUp(keyCode, event);
-    }
-
-    @Override
-    public void onStart() {
-        // Be sure to call the super class.
-        super.onStart();
-    }
-
-    @Override
-    public void onDestroy() {
-        mSessionManager.stop();
-        mPlayer.release();
-        mMediaSession.release();
-        mMediaRouter.removeCallback(mMediaRouterCB);
-        super.onDestroy();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(@NonNull Menu menu) {
-        // Be sure to call the super class.
-        super.onCreateOptionsMenu(menu);
-
-        // Inflate the menu and configure the media router action provider.
-        getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
-
-        MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
-        MediaRouteActionProvider mediaRouteActionProvider =
-                (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
-        if (mediaRouteActionProvider != null) {
-            mediaRouteActionProvider.setRouteSelector(mSelector);
-            mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
-                @NonNull
-                @Override
-                public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
-                    return new ControllerDialogFragment(MainActivity.this,
-                            mUseDefaultControlCheckBox);
-                }
-            });
-        }
-
-        // Return true to show the menu.
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
-        if (item.getItemId() == R.id.settings_menu_item) {
-            startActivity(new Intent(this, SettingsActivity.class));
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    void updateStatusFromSessionManager() {
+    private void updateStatusFromSessionManager() {
         if (mPlayer != null && mSessionManager != null) {
             mSessionManager.updateStatus();
         }
     }
 
-    void updateProgress() {
+    private void updateProgress() {
         // Estimate content position from last status time and elapsed time.
         // (Note this might be slightly out of sync with remote side, however
         // it avoids frequent polling the MRP.)
@@ -595,7 +583,7 @@
         mSeekBar.setProgress(progress);
     }
 
-    void updateUi() {
+    private void updateUi() {
         updatePlaylist();
         updateRouteDescription();
         updateButtons();
@@ -645,7 +633,8 @@
         mSeekBar.setEnabled(item != null && item.getDuration() > 0);
     }
 
-    PlaylistItem getCheckedPlaylistItem() {
+    @Nullable
+    private PlaylistItem getCheckedPlaylistItem() {
         int count = mPlayListView.getCount();
         int index = mPlayListView.getCheckedItemPosition();
         if (count > 0) {
@@ -659,7 +648,7 @@
     }
 
     @NonNull
-    public MediaRouterParams getRouterParams() {
+    private MediaRouterParams getRouterParams() {
         return new MediaRouterParams.Builder()
                 .setDialogType(MediaRouterParams.DIALOG_TYPE_DEFAULT)
                 .setTransferToLocalEnabled(true) // Phone speaker will be shown when casting.
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
index ade6898..aae3bd1 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/activities/SettingsActivity.java
@@ -52,7 +52,6 @@
     private MediaRouter mMediaRouter;
     private RoutesManager mRoutesManager;
     private RoutesAdapter mRoutesAdapter;
-    private RoutesAdapter.RouteItemListener mRouteItemListener;
     private SampleDynamicGroupMediaRouteProviderService mService;
     private ServiceConnection mConnection;
 
@@ -62,42 +61,39 @@
         setContentView(R.layout.activity_settings);
 
         mMediaRouter = MediaRouter.getInstance(this);
-
         mRoutesManager = RoutesManager.getInstance(getApplicationContext());
-
         mConnection = new ProviderServiceConnection();
 
         setUpViews();
 
-        mRouteItemListener =
-                new RoutesAdapter.RouteItemListener() {
-                    @Override
-                    public void onRouteEditClick(@NonNull String routeId) {
-                        AddEditRouteActivity.launchActivity(
-                                /* context= */ SettingsActivity.this, /* routeId */ routeId);
-                    }
+        RoutesAdapter.RouteItemListener routeItemListener = new RoutesAdapter.RouteItemListener() {
+            @Override
+            public void onRouteEditClick(@NonNull String routeId) {
+                AddEditRouteActivity.launchActivity(
+                        /* context= */ SettingsActivity.this, /* routeId */ routeId);
+            }
 
-                    @Override
-                    public void onRouteDeleteClick(@NonNull String routeId) {
-                        new AlertDialog.Builder(SettingsActivity.this)
-                                .setTitle("Delete this route?")
-                                .setMessage("Are you sure you want to delete this route?")
-                                .setPositiveButton(android.R.string.cancel, null)
-                                .setNegativeButton(
-                                        android.R.string.ok,
-                                        (dialogInterface, i) -> {
-                                            mRoutesManager.deleteRouteWithId(routeId);
-                                            mService.reloadRoutes();
-                                            mRoutesAdapter.updateRoutes(
-                                                    mRoutesManager.getRouteItems());
-                                        })
-                                .show();
-                    }
-                };
+            @Override
+            public void onRouteDeleteClick(@NonNull String routeId) {
+                new AlertDialog.Builder(SettingsActivity.this)
+                        .setTitle(R.string.delete_route_alert_dialog_title)
+                        .setMessage(R.string.delete_route_alert_dialog_message)
+                        .setPositiveButton(android.R.string.cancel, null)
+                        .setNegativeButton(
+                                android.R.string.ok,
+                                (dialogInterface, i) -> {
+                                    mRoutesManager.deleteRouteWithId(routeId);
+                                    mService.reloadRoutes();
+                                    mRoutesAdapter.updateRoutes(
+                                            mRoutesManager.getRouteItems());
+                                })
+                        .show();
+            }
+        };
 
         RecyclerView routeList = findViewById(R.id.routes_recycler_view);
         routeList.setLayoutManager(new LinearLayoutManager(/* context= */ this));
-        mRoutesAdapter = new RoutesAdapter(mRoutesManager.getRouteItems(), mRouteItemListener);
+        mRoutesAdapter = new RoutesAdapter(mRoutesManager.getRouteItems(), routeItemListener);
         routeList.setAdapter(mRoutesAdapter);
         routeList.setHasFixedSize(true);
     }
diff --git a/samples/MediaRoutingDemo/src/main/res/values/strings.xml b/samples/MediaRoutingDemo/src/main/res/values/strings.xml
index 34c1df3..8cc58fa 100644
--- a/samples/MediaRoutingDemo/src/main/res/values/strings.xml
+++ b/samples/MediaRoutingDemo/src/main/res/values/strings.xml
@@ -15,24 +15,16 @@
 -->
 
 <resources>
-    <string name="activity_sample_code">Media Routing Demo</string>
+    <string name="media_router_app_name">Media Routing Demo</string>
 
     <!-- MediaRouter -->
+    <string name="main_activity_label">Media Routing</string>
+    <string name="settings_activity_label">Settings</string>
+    <string name="add_edit_route_activity_label">Enter Route Details</string>
 
-    <string name="sample_media_router_activity_dark">MediaRouter/Dark Theme</string>
-    <string name="sample_media_router_activity_light">MediaRouter/Light Theme</string>
-    <string name="sample_media_router_activity_light_with_dark_action_bar">MediaRouter/Light Theme, Dark Action Bar</string>
-    <string name="sample_media_router_activity_dynamic_group">MediaRouter/Dynamic Group
-        Dialog</string>
-    <string name="sample_media_router_activity_output_switcher">MediaRouter/Output Switcher</string>
-    <string name="sample_media_router_activity_legacy">MediaRouter/Disable MediaRouter2</string>
-    <string name="sample_media_router_text">This activity demonstrates how to
-            use MediaRouter from the support library.  Select a route from the action bar.</string>
     <string name="media_route_menu_title">Play on...</string>
     <string name="settings_menu_item">Settings</string>
 
-    <string name="sample_media_route_settings_activity">Sample route settings</string>
-
     <string name="use_default_media_control">Use default media control</string>
     <string name="my_media_control_text">My Media Control</string>
 
@@ -61,5 +53,6 @@
     <string name="sample_media_route_activity_local">Local Playback</string>
     <string name="sample_media_route_activity_presentation">Local Playback on Presentation Display</string>
 
-    <string name="action_mode_done_content_description">Cancel</string>
+    <string name="delete_route_alert_dialog_title">Delete this route?</string>
+    <string name="delete_route_alert_dialog_message">Are you sure you want to delete this route?</string>
 </resources>
diff --git a/tv/tv-foundation/api/current.txt b/tv/tv-foundation/api/current.txt
index 3940a5b..9a5eb4c 100644
--- a/tv/tv-foundation/api/current.txt
+++ b/tv/tv-foundation/api/current.txt
@@ -101,6 +101,7 @@
   public sealed interface TvLazyGridLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -110,6 +111,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.grid.TvLazyGridItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
@@ -231,6 +233,7 @@
   public sealed interface TvLazyListLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -240,6 +243,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.list.TvLazyListItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
diff --git a/tv/tv-foundation/api/public_plus_experimental_current.txt b/tv/tv-foundation/api/public_plus_experimental_current.txt
index d9f30f7..950c887 100644
--- a/tv/tv-foundation/api/public_plus_experimental_current.txt
+++ b/tv/tv-foundation/api/public_plus_experimental_current.txt
@@ -107,6 +107,7 @@
   public sealed interface TvLazyGridLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -116,6 +117,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.grid.TvLazyGridItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
@@ -238,6 +240,7 @@
   public sealed interface TvLazyListLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -247,6 +250,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.list.TvLazyListItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
diff --git a/tv/tv-foundation/api/restricted_current.txt b/tv/tv-foundation/api/restricted_current.txt
index 3940a5b..9a5eb4c 100644
--- a/tv/tv-foundation/api/restricted_current.txt
+++ b/tv/tv-foundation/api/restricted_current.txt
@@ -101,6 +101,7 @@
   public sealed interface TvLazyGridLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -110,6 +111,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.grid.TvLazyGridItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
@@ -231,6 +233,7 @@
   public sealed interface TvLazyListLayoutInfo {
     method public int getAfterContentPadding();
     method public int getBeforeContentPadding();
+    method public int getMainAxisItemSpacing();
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -240,6 +243,7 @@
     method public java.util.List<androidx.tv.foundation.lazy.list.TvLazyListItemInfo> getVisibleItemsInfo();
     property public abstract int afterContentPadding;
     property public abstract int beforeContentPadding;
+    property public abstract int mainAxisItemSpacing;
     property public abstract androidx.compose.foundation.gestures.Orientation orientation;
     property public abstract boolean reverseLayout;
     property public abstract int totalItemsCount;
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyScrollAccessibilityTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
index a7bed08..aa11fda 100644
--- a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/lazy/grid/LazyScrollAccessibilityTest.kt
@@ -32,7 +32,6 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.testTag
@@ -41,15 +40,15 @@
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
-import androidx.compose.ui.unit.dp
 import androidx.core.view.ViewCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD
 import androidx.test.filters.MediumTest
 import com.google.common.truth.IterableSubject
 import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -100,6 +99,22 @@
                 .provider as AccessibilityNodeProvider
         }
 
+    private val itemSize = 21
+    private var itemSizeDp: Dp = Dp.Unspecified
+    private val containerSize = 200
+    private var containerSizeDp: Dp = Dp.Unspecified
+    private val contentPadding = 50
+    private var contentPaddingDp: Dp = Dp.Unspecified
+
+    @Before
+    fun before() {
+        with(rule.density) {
+            itemSizeDp = itemSize.toDp()
+            containerSizeDp = containerSize.toDp()
+            contentPaddingDp = contentPadding.toDp()
+        }
+    }
+
     @Test
     fun scrollForward() {
         testRelativeDirection(58, ACTION_SCROLL_FORWARD)
@@ -148,7 +163,6 @@
         )
     }
 
-    @Ignore // b/242180919
     @Test
     fun verifyScrollActionsAtEnd() {
         createScrollableContent_StartAtEnd()
@@ -277,13 +291,13 @@
     private fun createScrollableContent_StartInMiddle() {
         createScrollableContent {
             // Start at the middle:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> centered when 1000dp on either side, which is 47 items + 13dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> centered when 1000 on either side, which is 47 items + 13
             rememberTvLazyGridState(
                 47,
-                with(LocalDensity.current) { 13.dp.roundToPx() }
+                13
             )
         }
     }
@@ -294,19 +308,19 @@
     private fun createScrollableContent_StartAtEnd() {
         createScrollableContent {
             // Start at the end:
-            // Content size: 100 items * 21dp per item = 2100dp
-            // Viewport size: 200dp rect - 50dp padding on both sides = 100dp
-            // Content outside viewport: 2100dp - 100dp = 2000dp
-            // -> at the end when offset at 2000dp, which is 95 items + 5dp
+            // Content size: 100 items * 21 per item = 2100
+            // Viewport size: 200 rect - 50 padding on both sides = 100
+            // Content outside viewport: 2100 - 100 = 2000
+            // -> at the end when offset at 2000, which is 95 items + 5
             rememberTvLazyGridState(
                 95,
-                with(LocalDensity.current) { 5.dp.roundToPx() }
+                5
             )
         }
     }
 
     /**
-     * Creates a grid with a viewport of 100.dp, containing 100 items each 17.dp in size.
+     * Creates a grid with a viewport of 100 px, containing 100 items each 21 px in size.
      * The items have a text with their index (ASC), and where the viewport starts is determined
      * by the given [lambda][rememberTvLazyGridState]. All properties from [config] are applied.
      * The viewport has padding around it to make sure scroll distance doesn't include padding.
@@ -319,18 +333,18 @@
 
             val state = rememberTvLazyGridState()
 
-            Box(Modifier.requiredSize(200.dp).background(Color.White)) {
+            Box(Modifier.requiredSize(containerSizeDp).background(Color.White)) {
                 val direction = if (config.rtl) LayoutDirection.Rtl else LayoutDirection.Ltr
                 CompositionLocalProvider(LocalLayoutDirection provides direction) {
                     LazyGrid(
                         cells = 1,
                         modifier = Modifier.testTag(scrollerTag).matchParentSize(),
                         state = state,
-                        contentPadding = PaddingValues(50.dp),
+                        contentPadding = PaddingValues(contentPaddingDp),
                         reverseLayout = config.reversed
                     ) {
                         items(100) {
-                            Box(Modifier.requiredSize(21.dp).background(Color.Yellow)) {
+                            Box(Modifier.requiredSize(itemSizeDp).background(Color.Yellow)) {
                                 BasicText("$it", Modifier.align(Alignment.Center))
                             }
                         }
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 1d2de6dc..240856e 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
@@ -73,7 +73,8 @@
             totalItemsCount = 0,
             reverseLayout = reverseLayout,
             orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
-            afterContentPadding = afterContentPadding
+            afterContentPadding = afterContentPadding,
+            mainAxisItemSpacing = spaceBetweenLines
         )
     } else {
         var currentFirstLineIndex = firstVisibleLineIndex
@@ -266,7 +267,8 @@
             totalItemsCount = itemsCount,
             reverseLayout = reverseLayout,
             orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
-            afterContentPadding = afterContentPadding
+            afterContentPadding = afterContentPadding,
+            mainAxisItemSpacing = spaceBetweenLines
         )
     }
 }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridLayoutInfo.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridLayoutInfo.kt
index 6fc30dc..ef52f27 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridLayoutInfo.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridLayoutInfo.kt
@@ -80,4 +80,9 @@
      * For example it is a bottom content padding for LazyVerticalGrid with reverseLayout set to false.
      */
     val afterContentPadding: Int
+
+    /**
+     * The spacing between lines in the direction of scrolling.
+     */
+    val mainAxisItemSpacing: Int
 }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridMeasureResult.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridMeasureResult.kt
index 51bee04..e3bafd7 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridMeasureResult.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridMeasureResult.kt
@@ -51,7 +51,9 @@
     /** see [TvLazyGridLayoutInfo.orientation] */
     override val orientation: Orientation,
     /** see [TvLazyGridLayoutInfo.afterContentPadding] */
-    override val afterContentPadding: Int
+    override val afterContentPadding: Int,
+    /** see [TvLazyGridLayoutInfo.mainAxisItemSpacing] */
+    override val mainAxisItemSpacing: Int
 ) : TvLazyGridLayoutInfo, MeasureResult by measureResult {
     override val viewportSize: IntSize
         get() = IntSize(width, height)
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
index 52e13bf..c7474100 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/TvLazyGridState.kt
@@ -435,4 +435,5 @@
     override val reverseLayout = false
     override val beforeContentPadding: Int = 0
     override val afterContentPadding: Int = 0
+    override val mainAxisItemSpacing: Int = 0
 }
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 63c077e..aa938b9 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
@@ -76,7 +76,8 @@
             totalItemsCount = 0,
             reverseLayout = reverseLayout,
             orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
-            afterContentPadding = afterContentPadding
+            afterContentPadding = afterContentPadding,
+            mainAxisItemSpacing = spaceBetweenItems
         )
     } else {
         var currentFirstItemIndex = firstVisibleItemIndex
@@ -327,7 +328,8 @@
             totalItemsCount = itemsCount,
             reverseLayout = reverseLayout,
             orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
-            afterContentPadding = afterContentPadding
+            afterContentPadding = afterContentPadding,
+            mainAxisItemSpacing = spaceBetweenItems
         )
     }
 }
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasureResult.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasureResult.kt
index 16902ec..bc82bee 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasureResult.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListMeasureResult.kt
@@ -49,7 +49,9 @@
     /** see [TvLazyListLayoutInfo.orientation] */
     override val orientation: Orientation,
     /** see [TvLazyListLayoutInfo.afterContentPadding] */
-    override val afterContentPadding: Int
+    override val afterContentPadding: Int,
+    /** see [TvLazyListLayoutInfo.mainAxisItemSpacing] */
+    override val mainAxisItemSpacing: Int
 ) : TvLazyListLayoutInfo, MeasureResult by measureResult {
     override val viewportSize: IntSize
         get() = IntSize(width, height)
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
index 6e13d58..aae8340 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyListState.kt
@@ -428,6 +428,7 @@
     override val reverseLayout = false
     override val beforeContentPadding = 0
     override val afterContentPadding = 0
+    override val mainAxisItemSpacing = 0
 }
 
 internal class AwaitFirstLayoutModifier : OnGloballyPositionedModifier {
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/TvLazyListLayoutInfo.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/TvLazyListLayoutInfo.kt
index 89559d8..8f4aa89 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/TvLazyListLayoutInfo.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/TvLazyListLayoutInfo.kt
@@ -85,4 +85,10 @@
      */
     // DO NOT ADD DEFAULT get() HERE
     val afterContentPadding: Int
+
+    /**
+     * The spacing between items in the direction of scrolling.
+     */
+    // DO NOT ADD DEFAULT get() HERE
+    val mainAxisItemSpacing: Int
 }
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index 445b1fc..8a1701e 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -270,6 +270,42 @@
     field public static final androidx.wear.compose.material.PickerDefaults INSTANCE;
   }
 
+  public final class PickerGroupItem {
+    ctor public PickerGroupItem(androidx.wear.compose.material.PickerState pickerState, optional androidx.compose.ui.Modifier modifier, optional String? contentDescription, optional androidx.compose.ui.focus.FocusRequester? focusRequester, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> option);
+    method public String? getContentDescription();
+    method public androidx.compose.ui.focus.FocusRequester? getFocusRequester();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnSelected();
+    method public kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> getOption();
+    method public androidx.wear.compose.material.PickerState getPickerState();
+    method public kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? getReadOnlyLabel();
+    property public final String? contentDescription;
+    property public final androidx.compose.ui.focus.FocusRequester? focusRequester;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> onSelected;
+    property public final kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> option;
+    property public final androidx.wear.compose.material.PickerState pickerState;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel;
+  }
+
+  public final class PickerGroupKt {
+    method @androidx.compose.runtime.Composable public static void PickerGroup(androidx.wear.compose.material.PickerGroupItem![] pickers, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.PickerGroupState pickerGroupState, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onSelected, optional boolean autoCenter, optional androidx.wear.compose.material.TouchExplorationStateProvider touchExplorationStateProvider, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit>? separator);
+    method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerGroupState rememberPickerGroupState(optional int initiallySelectedIndex);
+  }
+
+  public final class PickerGroupState {
+    ctor public PickerGroupState(optional int initiallySelectedIndex);
+    method public int getSelectedIndex();
+    method public void setSelectedIndex(int);
+    property public final int selectedIndex;
+    field public static final androidx.wear.compose.material.PickerGroupState.Companion Companion;
+  }
+
+  public static final class PickerGroupState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> Saver;
+  }
+
   public final class PickerKt {
     method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
@@ -718,6 +754,10 @@
     method @androidx.compose.runtime.Composable public static void Switch(boolean checked, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwitchColors colors, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  public fun interface TouchExplorationStateProvider {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<java.lang.Boolean> touchExplorationState();
+  }
+
   @androidx.compose.runtime.Immutable public final class Typography {
     ctor public Typography(optional androidx.compose.ui.text.font.FontFamily defaultFontFamily, optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
     method public androidx.wear.compose.material.Typography copy(optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
diff --git a/wear/compose/compose-material/api/public_plus_experimental_current.txt b/wear/compose/compose-material/api/public_plus_experimental_current.txt
index d734539..8cc12b4 100644
--- a/wear/compose/compose-material/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-material/api/public_plus_experimental_current.txt
@@ -286,6 +286,42 @@
     field public static final androidx.wear.compose.material.PickerDefaults INSTANCE;
   }
 
+  public final class PickerGroupItem {
+    ctor public PickerGroupItem(androidx.wear.compose.material.PickerState pickerState, optional androidx.compose.ui.Modifier modifier, optional String? contentDescription, optional androidx.compose.ui.focus.FocusRequester? focusRequester, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> option);
+    method public String? getContentDescription();
+    method public androidx.compose.ui.focus.FocusRequester? getFocusRequester();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnSelected();
+    method public kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> getOption();
+    method public androidx.wear.compose.material.PickerState getPickerState();
+    method public kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? getReadOnlyLabel();
+    property public final String? contentDescription;
+    property public final androidx.compose.ui.focus.FocusRequester? focusRequester;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> onSelected;
+    property public final kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> option;
+    property public final androidx.wear.compose.material.PickerState pickerState;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel;
+  }
+
+  public final class PickerGroupKt {
+    method @androidx.compose.runtime.Composable public static void PickerGroup(androidx.wear.compose.material.PickerGroupItem![] pickers, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.PickerGroupState pickerGroupState, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onSelected, optional boolean autoCenter, optional androidx.wear.compose.material.TouchExplorationStateProvider touchExplorationStateProvider, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit>? separator);
+    method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerGroupState rememberPickerGroupState(optional int initiallySelectedIndex);
+  }
+
+  public final class PickerGroupState {
+    ctor public PickerGroupState(optional int initiallySelectedIndex);
+    method public int getSelectedIndex();
+    method public void setSelectedIndex(int);
+    property public final int selectedIndex;
+    field public static final androidx.wear.compose.material.PickerGroupState.Companion Companion;
+  }
+
+  public static final class PickerGroupState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> Saver;
+  }
+
   public final class PickerKt {
     method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
@@ -819,6 +855,10 @@
     method @androidx.compose.runtime.Composable public static void Switch(boolean checked, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwitchColors colors, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  public fun interface TouchExplorationStateProvider {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<java.lang.Boolean> touchExplorationState();
+  }
+
   @androidx.compose.runtime.Immutable public final class Typography {
     ctor public Typography(optional androidx.compose.ui.text.font.FontFamily defaultFontFamily, optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
     method public androidx.wear.compose.material.Typography copy(optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index 445b1fc..8a1701e 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -270,6 +270,42 @@
     field public static final androidx.wear.compose.material.PickerDefaults INSTANCE;
   }
 
+  public final class PickerGroupItem {
+    ctor public PickerGroupItem(androidx.wear.compose.material.PickerState pickerState, optional androidx.compose.ui.Modifier modifier, optional String? contentDescription, optional androidx.compose.ui.focus.FocusRequester? focusRequester, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, kotlin.jvm.functions.Function3<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> option);
+    method public String? getContentDescription();
+    method public androidx.compose.ui.focus.FocusRequester? getFocusRequester();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnSelected();
+    method public kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> getOption();
+    method public androidx.wear.compose.material.PickerState getPickerState();
+    method public kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? getReadOnlyLabel();
+    property public final String? contentDescription;
+    property public final androidx.compose.ui.focus.FocusRequester? focusRequester;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> onSelected;
+    property public final kotlin.jvm.functions.Function3<androidx.wear.compose.material.PickerScope,java.lang.Integer,java.lang.Boolean,kotlin.Unit> option;
+    property public final androidx.wear.compose.material.PickerState pickerState;
+    property public final kotlin.jvm.functions.Function1<androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel;
+  }
+
+  public final class PickerGroupKt {
+    method @androidx.compose.runtime.Composable public static void PickerGroup(androidx.wear.compose.material.PickerGroupItem![] pickers, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.PickerGroupState pickerGroupState, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> onSelected, optional boolean autoCenter, optional androidx.wear.compose.material.TouchExplorationStateProvider touchExplorationStateProvider, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit>? separator);
+    method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerGroupState rememberPickerGroupState(optional int initiallySelectedIndex);
+  }
+
+  public final class PickerGroupState {
+    ctor public PickerGroupState(optional int initiallySelectedIndex);
+    method public int getSelectedIndex();
+    method public void setSelectedIndex(int);
+    property public final int selectedIndex;
+    field public static final androidx.wear.compose.material.PickerGroupState.Companion Companion;
+  }
+
+  public static final class PickerGroupState.Companion {
+    method public androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> getSaver();
+    property public final androidx.compose.runtime.saveable.Saver<androidx.wear.compose.material.PickerGroupState,java.lang.Object> Saver;
+  }
+
   public final class PickerKt {
     method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
@@ -718,6 +754,10 @@
     method @androidx.compose.runtime.Composable public static void Switch(boolean checked, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwitchColors colors, optional boolean enabled, optional kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit>? onCheckedChange, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
   }
 
+  public fun interface TouchExplorationStateProvider {
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<java.lang.Boolean> touchExplorationState();
+  }
+
   @androidx.compose.runtime.Immutable public final class Typography {
     ctor public Typography(optional androidx.compose.ui.text.font.FontFamily defaultFontFamily, optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
     method public androidx.wear.compose.material.Typography copy(optional androidx.compose.ui.text.TextStyle display1, optional androidx.compose.ui.text.TextStyle display2, optional androidx.compose.ui.text.TextStyle display3, optional androidx.compose.ui.text.TextStyle title1, optional androidx.compose.ui.text.TextStyle title2, optional androidx.compose.ui.text.TextStyle title3, optional androidx.compose.ui.text.TextStyle body1, optional androidx.compose.ui.text.TextStyle body2, optional androidx.compose.ui.text.TextStyle button, optional androidx.compose.ui.text.TextStyle caption1, optional androidx.compose.ui.text.TextStyle caption2, optional androidx.compose.ui.text.TextStyle caption3);
diff --git a/wear/compose/compose-material/build.gradle b/wear/compose/compose-material/build.gradle
index 96b66ba..e1354a3 100644
--- a/wear/compose/compose-material/build.gradle
+++ b/wear/compose/compose-material/build.gradle
@@ -41,6 +41,7 @@
     implementation(project(":wear:compose:compose-foundation"))
     implementation(project(":wear:compose:compose-material-core"))
     implementation("androidx.profileinstaller:profileinstaller:1.2.0")
+    implementation("androidx.lifecycle:lifecycle-common:2.5.1")
 
     androidTestImplementation(project(":compose:ui:ui-test"))
     androidTestImplementation(project(":compose:ui:ui-test-junit4"))
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerGroupTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerGroupTest.kt
new file mode 100644
index 0000000..a58162b
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerGroupTest.kt
@@ -0,0 +1,154 @@
+/*
+ * 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.wear.compose.material
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+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 org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class PickerGroupTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun supports_test_tag() {
+        rule.setContentWithTheme {
+            PickerGroup(
+                pickers = getPickerColumns(1),
+                modifier = Modifier.testTag(TEST_TAG_1),
+                pickerGroupState = rememberPickerGroupState()
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG_1).assertExists()
+    }
+
+    @Test
+    fun state_returns_initially_selected_index_at_start() {
+        lateinit var pickerGroupState: PickerGroupState
+        val initiallySelectedColumn = 1
+        rule.setContentWithTheme {
+            PickerGroup(
+                pickers = getPickerColumns(2),
+                pickerGroupState = rememberPickerGroupState(initiallySelectedColumn).also {
+                    pickerGroupState = it
+                }
+            )
+        }
+
+        rule.waitForIdle()
+
+        assertThat(pickerGroupState.selectedIndex).isEqualTo(initiallySelectedColumn)
+    }
+
+    @Test
+    fun remember_pickerGroupState_after_updates() {
+        lateinit var selectedPicker: MutableState<Int>
+        rule.setContentWithTheme {
+            selectedPicker = remember { mutableStateOf(0) }
+            val pickerGroupState = rememberPickerGroupState(selectedPicker.value)
+            Text(text = "${pickerGroupState.selectedIndex}")
+        }
+
+        selectedPicker.value = 2
+        rule.waitForIdle()
+
+        rule.onNodeWithText("2").assertExists()
+    }
+    @Test
+    fun pickers_are_added_to_picker_group() {
+        val pickerColumnZero = getPickerColumnWithTag(TEST_TAG_1)
+        val pickerColumnOne = getPickerColumnWithTag(TEST_TAG_2)
+
+        rule.setContentWithTheme {
+            PickerGroup(pickerColumnZero, pickerColumnOne)
+        }
+
+        rule.onNodeWithTag(TEST_TAG_1).assertExists()
+        rule.onNodeWithTag(TEST_TAG_2).assertExists()
+    }
+
+    @Test
+    fun picker_changes_focus_when_clicked() {
+        lateinit var pickerGroupState: PickerGroupState
+        val touchExplorationStateProvider =
+            getTouchExplorationServiceState(touchExplorationServiceState = false)
+        val pickerColumnZero = getPickerColumnWithTag(TEST_TAG_1)
+        val pickerColumnOne = getPickerColumnWithTag(TEST_TAG_2)
+
+        rule.setContentWithTheme {
+            pickerGroupState = rememberPickerGroupState()
+            PickerGroup(
+                pickerColumnZero,
+                pickerColumnOne,
+                pickerGroupState = pickerGroupState,
+                touchExplorationStateProvider = touchExplorationStateProvider
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG_2).performClick()
+        rule.waitForIdle()
+
+        assertThat(pickerGroupState.selectedIndex).isEqualTo(1)
+    }
+
+    private fun getPickerColumns(count: Int): Array<PickerGroupItem> = Array(count) {
+        PickerGroupItem(pickerState = PickerState(10)) { _: Int, _: Boolean ->
+            Box(modifier = Modifier.size(20.dp))
+        }
+    }
+
+    private fun getPickerColumnWithTag(
+        tag: String,
+        onSelected: () -> Unit = {}
+    ): PickerGroupItem {
+        return PickerGroupItem(
+            pickerState = PickerState(10),
+            modifier = Modifier.testTag(tag),
+            onSelected = onSelected
+        ) { _: Int, _: Boolean ->
+            Box(modifier = Modifier.size(20.dp))
+        }
+    }
+
+    private fun getTouchExplorationServiceState(
+        touchExplorationServiceState: Boolean
+    ): TouchExplorationStateProvider {
+        return TouchExplorationStateProvider { rememberUpdatedState(touchExplorationServiceState) }
+    }
+
+    private val TEST_TAG_1 = "random string 1"
+    private val TEST_TAG_2 = "random string 2"
+}
\ No newline at end of file
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PickerGroup.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PickerGroup.kt
new file mode 100644
index 0000000..a6f1306
--- /dev/null
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PickerGroup.kt
@@ -0,0 +1,302 @@
+/*
+ * 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.wear.compose.material
+
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.scrollable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.listSaver
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.ParentDataModifier
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.unit.Density
+import androidx.wear.compose.foundation.HierarchicalFocusCoordinator
+import androidx.wear.compose.foundation.rememberActiveFocusRequester
+import kotlin.math.roundToInt
+import kotlinx.coroutines.coroutineScope
+
+/**
+ * A group of [Picker]s to build components where multiple pickers are required to be combined
+ * together.
+ * The component maintains the focus between different [Picker]s by using [PickerGroupState]. It can
+ * be handled from outside the component using the same instance and its properties.
+ * When touch exploration services are enabled, the focus moves to the picker which is clicked. To
+ * handle clicks in a different manner, use the [onSelected] lambda to control the focus of talkback
+ * and actual focus.
+ *
+ * It is recommended to ensure that a [Picker] in non read only mode should have user scroll enabled
+ * when touch exploration services are running.
+ *
+ * @param pickers List of [Picker]s represented using [PickerGroupItem] in the same order of
+ * display from left to right.
+ * @param modifier Modifier to be applied to the PickerGroup
+ * @param pickerGroupState The state of the component
+ * @param onSelected Action triggered when one of the [Picker] is selected inside the group
+ * @param autoCenter Indicates whether the selected [Picker] should be centered on the screen. It is
+ * recommended to set this as true when all the pickers cannot be fit into the screen. Or provide a
+ * mechanism to navigate to pickers which are not visible on screen. If false, the whole row
+ * containing pickers would be centered.
+ * @param touchExplorationStateProvider A [TouchExplorationStateProvider] to provide the current
+ * state of touch exploration service. This will be used to determine how the PickerGroup and
+ * talkback focus behaves/reacts to click and scroll events.
+ * @param separator A composable block which describes the separator between different [Picker]s.
+ * The integer parameter to the composable depicts the index where it will be kept. For example, 0
+ * would represent the separator between the first and second picker.
+ */
+@Composable
+public fun PickerGroup(
+    vararg pickers: PickerGroupItem,
+    modifier: Modifier = Modifier,
+    pickerGroupState: PickerGroupState = rememberPickerGroupState(),
+    onSelected: (selectedIndex: Int) -> Unit = {},
+    autoCenter: Boolean = true,
+    touchExplorationStateProvider: TouchExplorationStateProvider =
+        DefaultTouchExplorationStateProvider(),
+    separator: (@Composable (Int) -> Unit)? = null
+) {
+    val touchExplorationServicesEnabled by touchExplorationStateProvider.touchExplorationState()
+    AutoCenteringRow(
+        modifier = modifier
+            .then(
+                // When touch exploration services are enabled, send the scroll events on the parent
+                // composable to selected picker
+                if (touchExplorationServicesEnabled &&
+                    pickerGroupState.selectedIndex in pickers.indices) {
+                    Modifier.scrollablePicker(
+                        pickers[pickerGroupState.selectedIndex].pickerState
+                    )
+                } else {
+                    Modifier
+                }
+            ),
+    ) {
+        pickers.forEachIndexed { index, pickerData ->
+            val pickerSelected = index == pickerGroupState.selectedIndex
+            val flingBehavior = PickerDefaults.flingBehavior(state = pickerData.pickerState)
+            HierarchicalFocusCoordinator(requiresFocus = { pickerSelected }) {
+                val focusRequester =
+                    pickerData.focusRequester ?: rememberActiveFocusRequester()
+                Picker(
+                    state = pickerData.pickerState,
+                    contentDescription = pickerData.contentDescription,
+                    readOnly = !pickerSelected,
+                    modifier = pickerData.modifier
+                        .then(
+                            // If auto center is enabled, apply auto centering modifier on selected
+                            // picker to center it
+                            if (pickerSelected && autoCenter) Modifier.autoCenteringTarget()
+                            else Modifier
+                        )
+                        .focusRequester(focusRequester),
+                    readOnlyLabel = pickerData.readOnlyLabel,
+                    flingBehavior = flingBehavior,
+                    onSelected = pickerData.onSelected,
+                    userScrollEnabled = !touchExplorationServicesEnabled || pickerSelected,
+                    option = { optionIndex ->
+                        with(pickerData) {
+                            Box(
+                                if (touchExplorationServicesEnabled || pickerSelected) {
+                                    Modifier
+                                } else Modifier.pointerInput(Unit) {
+                                    coroutineScope {
+                                        // Keep looking for touch events on the picker if it is not
+                                        // selected
+                                        while (true) {
+                                            awaitEachGesture {
+                                                awaitFirstDown(requireUnconsumed = false)
+                                                pickerGroupState.selectedIndex = index
+                                                onSelected(index)
+                                            }
+                                        }
+                                    }
+                                }
+                            ) {
+                                option(optionIndex, pickerSelected)
+                            }
+                        }
+                    }
+                )
+            }
+            if (index < pickers.size - 1) {
+                separator?.invoke(index)
+            }
+        }
+    }
+}
+
+/**
+ * Creates a [PickerGroupState] that is remembered across compositions.
+ *
+ * @param initiallySelectedIndex the picker index that will be initially focused
+ */
+@Composable
+public fun rememberPickerGroupState(
+    initiallySelectedIndex: Int = 0
+): PickerGroupState = rememberSaveable(
+    initiallySelectedIndex,
+    saver = PickerGroupState.Saver
+) {
+    PickerGroupState(initiallySelectedIndex)
+}
+
+/**
+ * A state object that can be used to observe the selected [Picker].
+ *
+ * @param initiallySelectedIndex the picker index that will be initially selected
+ */
+public class PickerGroupState constructor(
+    initiallySelectedIndex: Int = 0,
+) {
+
+    /**
+     * The current selected [Picker] index.
+     */
+    var selectedIndex by mutableStateOf(initiallySelectedIndex)
+
+    public companion object {
+        val Saver = listSaver<PickerGroupState, Any?>(
+            save = {
+                listOf(
+                    it.selectedIndex
+                )
+            },
+            restore = { saved ->
+                PickerGroupState(
+                    initiallySelectedIndex = saved[0] as Int
+                )
+            }
+        )
+    }
+}
+
+/**
+ * A class for representing [Picker] which will be composed inside a [PickerGroup].
+ *
+ * @param pickerState The state of the picker
+ * @param modifier Modifier to be applied to the Picker
+ * @param contentDescription Text used by accessibility services to describe what the
+ * selected option represents. This text should be localized, such as by using
+ * [androidx.compose.ui.res.stringResource] or similar. Typically, the content description is
+ * inferred via derivedStateOf to avoid unnecessary recompositions, like this:
+ * val description by remember { derivedStateOf { /* expression using state.selectedOption */ } }
+ * @param focusRequester Optional [FocusRequester] for the [Picker]. If not provided, a local
+ * instance of [FocusRequester] will be created to handle the focus between different pickers
+ * @param onSelected Action triggered when the Picker is selected by clicking
+ * @param readOnlyLabel A slot for providing a label, displayed above the selected option
+ * when the [Picker] is read-only. The label is overlaid with the currently selected
+ * option within a Box, so it is recommended that the label is given [Alignment.TopCenter].
+ * @param option A block which describes the content. The integer parameter to the composable
+ * denotes the index of the option and boolean denotes whether the picker is selected or not.
+ */
+public class PickerGroupItem(
+    val pickerState: PickerState,
+    val modifier: Modifier = Modifier,
+    val contentDescription: String? = null,
+    val focusRequester: FocusRequester? = null,
+    val onSelected: () -> Unit = {},
+    val readOnlyLabel: @Composable (BoxScope.() -> Unit)? = null,
+    val option: @Composable PickerScope.(optionIndex: Int, pickerSelected: Boolean) -> Unit
+)
+
+/*
+ * A row that horizontally aligns the center of the first child that has
+ * Modifier.autoCenteringTarget() with the center of this row.
+ * If no child has that modifier, the whole row is horizontally centered.
+ * Vertically, each child is centered.
+ */
+@Composable
+private fun AutoCenteringRow(
+    modifier: Modifier = Modifier,
+    content: @Composable () -> Unit
+) {
+    Layout(modifier = modifier, content = content) { measurables, constraints ->
+        val placeables = measurables.map { it.measure(constraints) }
+        val centeringOffset = computeCenteringOffset(placeables)
+        val rowWidth =
+            if (constraints.hasBoundedWidth) constraints.maxWidth
+            else constraints.minWidth
+        val rowHeight =
+            if (constraints.hasBoundedHeight) constraints.maxHeight
+            else constraints.minHeight
+        layout(width = rowWidth, height = rowHeight) {
+            var x = rowWidth / 2f - centeringOffset
+            placeables.forEach {
+                it.placeRelative(x.roundToInt(), ((rowHeight - it.height) / 2f).roundToInt())
+                x += it.width
+            }
+        }
+    }
+}
+
+/**
+ * A scrollable modifier which can be applied on a composable to propagate the scrollable events to
+ * the specified [Picker] defined by the [PickerState].
+ */
+private fun Modifier.scrollablePicker(
+    pickerState: PickerState
+) = Modifier.composed {
+    this.scrollable(
+        state = pickerState,
+        orientation = Orientation.Vertical,
+        flingBehavior = PickerDefaults.flingBehavior(state = pickerState),
+        reverseDirection = true
+    )
+}
+
+/**
+ * Calculates the center for the list of [Placeable]. Returns the offset which can be applied on
+ * parent composable to center the contents. If [autoCenteringTarget] is applied to any [Placeable],
+ * the offset returned will allow to center that particular composable.
+ */
+private fun computeCenteringOffset(placeables: List<Placeable>): Int {
+    var sumWidth = 0
+    placeables.forEach { p ->
+        if (p.isAutoCenteringTarget()) {
+            // The target centering offset is at the middle of this child.
+            return sumWidth + p.width / 2
+        }
+        sumWidth += p.width
+    }
+
+    // No target, center the whole row.
+    return sumWidth / 2
+}
+
+@Suppress("ModifierInspectorInfo")
+internal fun Modifier.autoCenteringTarget() = this.then(
+    object : ParentDataModifier {
+        override fun Density.modifyParentData(parentData: Any?) = AutoCenteringRowParentData()
+    }
+)
+
+internal class AutoCenteringRowParentData
+
+internal fun Placeable.isAutoCenteringTarget() = (parentData as? AutoCenteringRowParentData) != null
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TouchExplorationStateProvider.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TouchExplorationStateProvider.kt
new file mode 100644
index 0000000..e8a261e
--- /dev/null
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/TouchExplorationStateProvider.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.wear.compose.material
+
+import android.content.Context
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+
+/**
+ * A functional interface for providing the state of touch exploration services. It is strongly
+ * discouraged to make logic conditional based on state of accessibility services. Please consult
+ * with accessibility experts before making such change.
+ */
+public fun interface TouchExplorationStateProvider {
+
+    /**
+     * Returns the touch exploration service state wrapped in a [State] to allow composables to
+     * attach the state to itself. This will allow composables to react to change in service state,
+     * if required.
+     */
+    @Composable
+    fun touchExplorationState(): State<Boolean>
+}
+
+/**
+ * The default implementation of [TouchExplorationStateProvider]. It depends on the state of
+ * accessibility services to determine the current state of touch exploration services.
+ */
+internal class DefaultTouchExplorationStateProvider : TouchExplorationStateProvider {
+
+    @Composable
+    public override fun touchExplorationState(): State<Boolean> {
+        val context = LocalContext.current
+        val accessibilityManager = remember {
+            context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
+        }
+
+        val listener = remember { Listener() }
+
+        LocalLifecycleOwner.current.lifecycle.ObserveState(
+            handleEvent = { event ->
+                if (event == Lifecycle.Event.ON_RESUME) {
+                    listener.register(accessibilityManager)
+                }
+            },
+            onDispose = {
+                listener.unregister(accessibilityManager)
+            }
+        )
+
+        return remember { derivedStateOf { listener.isEnabled() } }
+    }
+
+    @Composable
+    private fun Lifecycle.ObserveState(
+        handleEvent: (Lifecycle.Event) -> Unit = {},
+        onDispose: () -> Unit = {}
+    ) {
+        DisposableEffect(this) {
+            val observer = LifecycleEventObserver { _, event ->
+                handleEvent(event)
+            }
+            [email protected](observer)
+            onDispose {
+                onDispose()
+                [email protected](observer)
+            }
+        }
+    }
+
+    private class Listener : AccessibilityStateChangeListener, TouchExplorationStateChangeListener {
+        private var accessibilityEnabled by mutableStateOf(false)
+        private var touchExplorationEnabled by mutableStateOf(false)
+
+        fun isEnabled() = accessibilityEnabled && touchExplorationEnabled
+
+        override fun onAccessibilityStateChanged(it: Boolean) {
+            accessibilityEnabled = it
+        }
+
+        override fun onTouchExplorationStateChanged(it: Boolean) {
+            touchExplorationEnabled = it
+        }
+
+        fun register(am: AccessibilityManager) {
+            accessibilityEnabled = am.isEnabled
+            touchExplorationEnabled = am.isTouchExplorationEnabled
+
+            am.addTouchExplorationStateChangeListener(this)
+            am.addAccessibilityStateChangeListener(this)
+        }
+
+        fun unregister(am: AccessibilityManager) {
+            am.removeTouchExplorationStateChangeListener(this)
+            am.removeAccessibilityStateChangeListener(this)
+        }
+    }
+}
\ No newline at end of file
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
index 11cadf3..1eebca8 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
@@ -21,6 +21,7 @@
 import android.os.Build
 import android.view.MotionEvent
 import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
 import androidx.annotation.RequiresApi
 import androidx.compose.foundation.gestures.FlingBehavior
@@ -45,7 +46,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -73,10 +74,15 @@
 import androidx.wear.compose.material.Icon
 import androidx.wear.compose.material.MaterialTheme
 import androidx.wear.compose.material.Picker
+import androidx.wear.compose.material.PickerGroupItem
 import androidx.wear.compose.material.PickerDefaults
+import androidx.wear.compose.material.PickerGroup
+import androidx.wear.compose.material.PickerGroupState
 import androidx.wear.compose.material.PickerScope
 import androidx.wear.compose.material.PickerState
+import androidx.wear.compose.material.TouchExplorationStateProvider
 import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.rememberPickerGroupState
 import androidx.wear.compose.material.rememberPickerState
 import java.time.LocalDate
 import java.time.LocalTime
@@ -84,9 +90,6 @@
 import java.time.temporal.ChronoField
 import java.time.temporal.TemporalAdjusters
 
-private var touchExplorationEnabled = false
-private lateinit var touchExplorationStateChangeListener: TouchExplorationStateChangeListener
-
 /**
  * A full screen TimePicker with hours, minutes and seconds.
  *
@@ -125,59 +128,58 @@
         initialNumberOfOptions = 60,
         initiallySelectedOption = time.second
     )
-    val talkbackEnabled by rememberTalkBackState()
+    val touchExplorationServicesEnabled by DefaultTouchExplorationStateProvider()
+        .touchExplorationState()
 
     MaterialTheme(typography = typography) {
         // When the time picker loads, none of the individual pickers are selected in talkback mode,
         // otherwise hours picker should be focused.
-        var focusedElement by remember {
-            mutableStateOf(
-                if (talkbackEnabled) FocusableElement.NONE else FocusableElement.HOURS
-            )
+        val pickerGroupState = if (touchExplorationServicesEnabled) {
+            rememberPickerGroupState(-1)
+        } else {
+            rememberPickerGroupState(0)
         }
         val textStyle = MaterialTheme.typography.display3
         val optionColor = MaterialTheme.colors.secondary
-        val focusRequesterHours = remember { FocusRequester() }
-        val focusRequesterMinutes = remember { FocusRequester() }
-        val focusRequesterSeconds = remember { FocusRequester() }
+        val pickerOption = pickerTextOption(textStyle) { "%02d".format(it) }
         val focusRequesterConfirmButton = remember { FocusRequester() }
 
-        val hourContentDescription by remember { derivedStateOf {
-            createDescription(focusedElement, hourState.selectedOption, "hours")
-        } }
-        val minuteContentDescription by remember { derivedStateOf {
-            createDescription(focusedElement, minuteState.selectedOption, "minutes")
-        } }
-        val secondContentDescription by remember { derivedStateOf {
-            createDescription(focusedElement, secondState.selectedOption, "seconds")
-        } }
+        val hourContentDescription by remember {
+            derivedStateOf {
+                createDescription(pickerGroupState, hourState.selectedOption, "hours")
+            }
+        }
+        val minuteContentDescription by remember {
+            derivedStateOf {
+                createDescription(pickerGroupState, minuteState.selectedOption, "minutes")
+            }
+        }
+        val secondContentDescription by remember {
+            derivedStateOf {
+                createDescription(pickerGroupState, secondState.selectedOption, "seconds")
+            }
+        }
+        val onPickerSelected = { selectedPicker: Int ->
+            if (pickerGroupState.selectedIndex != selectedPicker) {
+                pickerGroupState.selectedIndex = selectedPicker
+            } else if (selectedPicker > 2) {
+                focusRequesterConfirmButton.requestFocus()
+            } else {
+                pickerGroupState.selectedIndex += 1
+            }
+        }
 
-        Box(
-            modifier = modifier
-                .fillMaxSize()
-                .then(
-                    if (talkbackEnabled) {
-                        when (focusedElement) {
-                            FocusableElement.HOURS -> Modifier.scrollablePicker(hourState)
-                            FocusableElement.MINUTES -> Modifier.scrollablePicker(minuteState)
-                            FocusableElement.SECONDS -> Modifier.scrollablePicker(secondState)
-                            else -> Modifier
-                        }
-                    } else {
-                        Modifier
-                    }
-                )
-        ) {
+        Box(modifier = modifier.fillMaxSize()) {
             Column(
                 verticalArrangement = Arrangement.Center,
                 horizontalAlignment = Alignment.CenterHorizontally
             ) {
                 Spacer(Modifier.height(12.dp))
                 Text(
-                    text = when (focusedElement) {
-                        FocusableElement.HOURS -> "Hour"
-                        FocusableElement.MINUTES -> "Minute"
-                        FocusableElement.SECONDS -> "Second"
+                    text = when (pickerGroupState.selectedIndex) {
+                        0 -> "Hour"
+                        1 -> "Minute"
+                        2 -> "Second"
                         else -> ""
                     },
                     color = optionColor,
@@ -195,86 +197,35 @@
                     verticalAlignment = Alignment.CenterVertically,
                     horizontalArrangement = Arrangement.Center,
                 ) {
-                    val doubleTapToNext = { position: FocusableElement, next: FocusableElement ->
-                        focusedElement = when (focusedElement) {
-                            position -> next
-                            else -> position
-                        }
-                    }
-                    PickerWithRSB(
-                        readOnly = focusedElement != FocusableElement.HOURS,
-                        state = hourState,
-                        focusRequester = focusRequesterHours,
-                        modifier = Modifier.size(40.dp, 100.dp),
-                        onSelected = {
-                                doubleTapToNext(FocusableElement.HOURS, FocusableElement.MINUTES)
-                        },
-                        contentDescription = hourContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
-                            focusedElement == FocusableElement.HOURS
-                    ) { hour: Int ->
-                        TimePiece(
-                            selected = focusedElement == FocusableElement.HOURS,
-                            onSelected = {
-                                doubleTapToNext(FocusableElement.HOURS, FocusableElement.MINUTES)
-                            },
-                            text = "%02d".format(hour),
-                            style = textStyle,
-                            talkbackEnabled = talkbackEnabled
-                        )
-                    }
-                    Separator(6.dp, textStyle)
-                    PickerWithRSB(
-                        readOnly = focusedElement != FocusableElement.MINUTES,
-                        state = minuteState,
-                        focusRequester = focusRequesterMinutes,
-                        modifier = Modifier.size(40.dp, 100.dp),
-                        onSelected = {
-                            doubleTapToNext(FocusableElement.MINUTES, FocusableElement.SECONDS)
-                        },
-                        contentDescription = minuteContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
-                            focusedElement == FocusableElement.MINUTES
-                    ) { minute: Int ->
-                        TimePiece(
-                            selected = focusedElement == FocusableElement.MINUTES,
-                            onSelected = {
-                                doubleTapToNext(FocusableElement.MINUTES, FocusableElement.SECONDS)
-                            },
-                            text = "%02d".format(minute),
-                            style = textStyle,
-                            talkbackEnabled = talkbackEnabled
-                        )
-                    }
-                    Separator(6.dp, textStyle)
-                    PickerWithRSB(
-                        readOnly = focusedElement != FocusableElement.SECONDS,
-                        state = secondState,
-                        focusRequester = focusRequesterSeconds,
-                        modifier = Modifier.size(40.dp, 100.dp),
-                        onSelected = {
-                            doubleTapToNext(
-                                FocusableElement.SECONDS,
-                                FocusableElement.CONFIRM_BUTTON
-                            )
-                        },
-                        contentDescription = secondContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
-                            focusedElement == FocusableElement.SECONDS
-                    ) { second: Int ->
-                        TimePiece(
-                            selected = focusedElement == FocusableElement.SECONDS,
-                            onSelected = {
-                                doubleTapToNext(
-                                    FocusableElement.SECONDS,
-                                    FocusableElement.CONFIRM_BUTTON
-                                )
-                            },
-                            text = "%02d".format(second),
-                            style = textStyle,
-                            talkbackEnabled = talkbackEnabled
-                        )
-                    }
+                    PickerGroup(
+                        PickerGroupItem(
+                            pickerState = hourState,
+                            modifier = Modifier.size(40.dp, 100.dp),
+                            focusRequester = remember { FocusRequester() },
+                            onSelected = { onPickerSelected(0) },
+                            contentDescription = hourContentDescription,
+                            option = pickerOption
+                        ),
+                        PickerGroupItem(
+                            pickerState = minuteState,
+                            modifier = Modifier.size(40.dp, 100.dp),
+                            focusRequester = remember { FocusRequester() },
+                            onSelected = { onPickerSelected(1) },
+                            contentDescription = minuteContentDescription,
+                            option = pickerOption
+                        ),
+                        PickerGroupItem(
+                            pickerState = secondState,
+                            modifier = Modifier.size(40.dp, 100.dp),
+                            focusRequester = remember { FocusRequester() },
+                            onSelected = { onPickerSelected(2) },
+                            contentDescription = secondContentDescription,
+                            option = pickerOption
+                        ),
+                        pickerGroupState = pickerGroupState,
+                        separator = { Separator(6.dp, textStyle) },
+                        autoCenter = false
+                    )
                 }
                 Spacer(
                     Modifier
@@ -292,7 +243,7 @@
                     },
                     modifier = Modifier
                         .semantics {
-                            focused = focusedElement == FocusableElement.CONFIRM_BUTTON
+                            focused = pickerGroupState.selectedIndex > 2
                         }
                         .focusRequester(focusRequesterConfirmButton)
                 ) {
@@ -306,14 +257,6 @@
                 }
                 Spacer(Modifier.height(12.dp))
             }
-            LaunchedEffect(focusedElement) {
-                if (focusedElement != FocusableElement.NONE) {
-                    listOf(
-                        focusRequesterHours, focusRequesterMinutes, focusRequesterSeconds,
-                        focusRequesterConfirmButton
-                    )[focusedElement.index].requestFocus()
-                }
-            }
         }
     }
 }
@@ -357,12 +300,14 @@
         initiallySelectedOption = time[ChronoField.AMPM_OF_DAY],
         repeatItems = false
     )
-    val talkbackEnabled by rememberTalkBackState()
+    val touchExplorationServicesEnabled by DefaultTouchExplorationStateProvider()
+        .touchExplorationState()
 
     MaterialTheme(typography = typography) {
         var focusedElement by remember {
             mutableStateOf(
-                if (talkbackEnabled) FocusableElement12Hour.NONE else FocusableElement12Hour.HOURS
+                if (touchExplorationServicesEnabled) FocusableElement12Hour.NONE
+                else FocusableElement12Hour.HOURS
             )
         }
         val textStyle = MaterialTheme.typography.display3
@@ -395,7 +340,7 @@
             modifier = modifier
                 .fillMaxSize()
                 .then(
-                    if (talkbackEnabled) {
+                    if (touchExplorationServicesEnabled) {
                         when (focusedElement) {
                             FocusableElement12Hour.HOURS -> Modifier.scrollablePicker(hourState)
                             FocusableElement12Hour.MINUTES -> Modifier.scrollablePicker(minuteState)
@@ -454,7 +399,7 @@
                             )
                         },
                         contentDescription = hoursContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
+                        userScrollEnabled = !touchExplorationServicesEnabled ||
                             focusedElement == FocusableElement12Hour.HOURS
                     ) { hour: Int ->
                         TimePiece(
@@ -467,7 +412,7 @@
                             },
                             text = "%02d".format(hour + 1),
                             style = textStyle,
-                            talkbackEnabled = talkbackEnabled
+                            touchExplorationServicesEnabled = touchExplorationServicesEnabled
                         )
                     }
                     Separator(2.dp, textStyle)
@@ -483,7 +428,7 @@
                             )
                         },
                         contentDescription = minutesContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
+                        userScrollEnabled = !touchExplorationServicesEnabled ||
                             focusedElement == FocusableElement12Hour.MINUTES
                     ) { minute: Int ->
                         TimePiece(
@@ -496,7 +441,7 @@
                             },
                             text = "%02d".format(minute),
                             style = textStyle,
-                            talkbackEnabled = talkbackEnabled
+                            touchExplorationServicesEnabled = touchExplorationServicesEnabled
                         )
                     }
                     Spacer(Modifier.width(6.dp))
@@ -512,7 +457,7 @@
                             )
                         },
                         contentDescription = periodContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
+                        userScrollEnabled = !touchExplorationServicesEnabled ||
                             focusedElement == FocusableElement12Hour.PERIOD
                     ) { period: Int ->
                         TimePiece(
@@ -525,7 +470,7 @@
                             },
                             text = if (period == 0) amString else pmString,
                             style = textStyle,
-                            talkbackEnabled = talkbackEnabled
+                            touchExplorationServicesEnabled = touchExplorationServicesEnabled
                         )
                     }
                 }
@@ -615,12 +560,13 @@
             fontSize = with(LocalDensity.current) { 34.dp.toSp() }
         )
     )
-    val talkbackEnabled by rememberTalkBackState()
+    val touchExplorationServicesEnabled by DefaultTouchExplorationStateProvider()
+        .touchExplorationState()
 
     MaterialTheme(typography = typography) {
         var focusedElement by remember {
             mutableStateOf(
-                if (talkbackEnabled)
+                if (touchExplorationServicesEnabled)
                     FocusableElementDatePicker.NONE else FocusableElementDatePicker.DAY
             )
         }
@@ -669,14 +615,17 @@
             modifier = modifier
                 .fillMaxSize()
                 .then(
-                    if (talkbackEnabled) {
+                    if (touchExplorationServicesEnabled) {
                         when (focusedElement) {
                             FocusableElementDatePicker.DAY ->
                                 Modifier.scrollablePicker(datePickerState.dayState)
+
                             FocusableElementDatePicker.MONTH ->
                                 Modifier.scrollablePicker(datePickerState.monthState)
+
                             FocusableElementDatePicker.YEAR ->
                                 Modifier.scrollablePicker(datePickerState.yearState)
+
                             else -> Modifier
                         }
                     } else {
@@ -744,9 +693,9 @@
                             width = dayWidth,
                             focusRequester = focusRequesterDay,
                             contentDescription = dayContentDescription,
-                            userScrollEnabled = !talkbackEnabled ||
+                            userScrollEnabled = !touchExplorationServicesEnabled ||
                                 focusedElement == FocusableElementDatePicker.DAY,
-                            talkbackEnabled = talkbackEnabled
+                            touchExplorationServicesEnabled = touchExplorationServicesEnabled
                         )
                         Spacer(modifier = Modifier.width(spacerWidth))
                     }
@@ -764,9 +713,9 @@
                         width = monthWidth,
                         focusRequester = focusRequesterMonth,
                         contentDescription = monthContentDescription,
-                        userScrollEnabled = !talkbackEnabled ||
+                        userScrollEnabled = !touchExplorationServicesEnabled ||
                             focusedElement == FocusableElementDatePicker.MONTH,
-                        talkbackEnabled = talkbackEnabled
+                        touchExplorationServicesEnabled = touchExplorationServicesEnabled
                     )
                     if (focusedElement.index > 0) {
                         Spacer(modifier = Modifier.width(spacerWidth))
@@ -783,9 +732,9 @@
                             width = yearWidth,
                             focusRequester = focusRequesterYear,
                             contentDescription = yearContentDescription,
-                            userScrollEnabled = !talkbackEnabled ||
+                            userScrollEnabled = !touchExplorationServicesEnabled ||
                                 focusedElement == FocusableElementDatePicker.YEAR,
-                            talkbackEnabled = talkbackEnabled
+                            touchExplorationServicesEnabled = touchExplorationServicesEnabled
                         )
                     }
                 }
@@ -854,7 +803,7 @@
     width: Dp,
     contentDescription: String,
     userScrollEnabled: Boolean,
-    talkbackEnabled: Boolean
+    touchExplorationServicesEnabled: Boolean
 ) {
     PickerWithRSB(
         readOnly = readOnly,
@@ -870,7 +819,7 @@
             onSelected = onSelected,
             text = text(option),
             style = MaterialTheme.typography.display2,
-            talkbackEnabled = talkbackEnabled
+            touchExplorationServicesEnabled = touchExplorationServicesEnabled
         )
     }
 }
@@ -882,7 +831,7 @@
     onSelected: () -> Unit,
     text: String,
     style: TextStyle,
-    talkbackEnabled: Boolean = false
+    touchExplorationServicesEnabled: Boolean = false
 ) {
     Box(modifier = Modifier.fillMaxSize()) {
         val modifier = Modifier
@@ -896,7 +845,7 @@
             if (selected) MaterialTheme.colors.secondary
             else MaterialTheme.colors.onBackground,
             modifier =
-            if (selected || talkbackEnabled) modifier
+            if (selected || touchExplorationServicesEnabled) modifier
             else modifier.pointerInteropFilter {
                 if (it.action == MotionEvent.ACTION_DOWN) onSelected()
                 true
@@ -971,49 +920,21 @@
     }
 }
 
-@Composable
-private fun rememberTalkBackState(): MutableState<Boolean> {
-    val context = LocalContext.current
-    val accessibilityManager = setupAccessibilityManager(context)
-    var initialContent by remember { mutableStateOf(true) }
-
-    if (initialContent) {
-        touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
-        initialContent = false
-    }
-    var talkbackEnabled = remember {
-        mutableStateOf(accessibilityManager.isEnabled && touchExplorationEnabled)
-    }
-
-    LocalLifecycleOwner.current.lifecycle.ObserveState(
-        handleEvent = { event ->
-            if (event == Lifecycle.Event.ON_RESUME) {
-                talkbackEnabled.value = accessibilityManager.isEnabled && touchExplorationEnabled
-            }
-        },
-        onDispose = {
-            accessibilityManager.removeTouchExplorationStateChangeListener(
-                touchExplorationStateChangeListener
-            )
-        }
-    )
-    return talkbackEnabled
-}
-
-@Composable
-fun Lifecycle.ObserveState(
-    handleEvent: (Lifecycle.Event) -> Unit = {},
-    onDispose: () -> Unit = {}
-) {
-    DisposableEffect(this) {
-        val observer = LifecycleEventObserver { _, event ->
-            handleEvent(event)
-        }
-        [email protected](observer)
-        onDispose {
-            onDispose()
-            [email protected](observer)
-        }
+private fun pickerTextOption(textStyle: TextStyle, indexToText: (Int) -> String):
+    (@Composable PickerScope.(optionIndex: Int, pickerSelected: Boolean) -> Unit) = {
+        value: Int, pickerSelected: Boolean ->
+    Box(modifier = Modifier.fillMaxSize()) {
+        Text(
+            text = indexToText(value),
+            maxLines = 1,
+            style = textStyle,
+            color =
+            if (pickerSelected) MaterialTheme.colors.secondary
+            else MaterialTheme.colors.onBackground,
+            modifier = Modifier
+                .align(Alignment.Center)
+                .wrapContentSize()
+        )
     }
 }
 
@@ -1028,31 +949,13 @@
     )
 }
 
-private fun setupAccessibilityManager(context: Context): AccessibilityManager {
-    val accessibilityManager =
-        context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
-    accessibilityManager.addTouchExplorationStateChangeListener(
-        touchExplorationStateListener()
-    )
-    return accessibilityManager
-}
-
-private fun touchExplorationStateListener(): TouchExplorationStateChangeListener {
-    touchExplorationStateChangeListener = TouchExplorationStateChangeListener { isEnabled ->
-        touchExplorationEnabled = isEnabled
-    }
-    return touchExplorationStateChangeListener
-}
-
 private fun createDescription(
-    focusedElement: FocusableElement,
+    pickerGroupState: PickerGroupState,
     selectedValue: Int,
     label: String
 ): String {
-    return when (focusedElement) {
-        FocusableElement.NONE -> {
-            label
-        }
+    return when (pickerGroupState.selectedIndex) {
+        -1 -> label
         else -> "$selectedValue" + label
     }
 }
@@ -1180,12 +1083,78 @@
     }
 }
 
-enum class FocusableElement(val index: Int) {
-    HOURS(0),
-    MINUTES(1),
-    SECONDS(2),
-    CONFIRM_BUTTON(3),
-    NONE(-1)
+/**
+ * This is copied from [TouchExplorationStateProvider]. Please updated if something changes over there.
+ */
+private class DefaultTouchExplorationStateProvider : TouchExplorationStateProvider {
+
+    @Composable
+    public override fun touchExplorationState(): State<Boolean> {
+        val context = LocalContext.current
+        val accessibilityManager = remember {
+            context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
+        }
+
+        val listener = remember { Listener() }
+
+        LocalLifecycleOwner.current.lifecycle.ObserveState(
+            handleEvent = { event ->
+                if (event == Lifecycle.Event.ON_RESUME) {
+                    listener.register(accessibilityManager)
+                }
+            },
+            onDispose = {
+                listener.unregister(accessibilityManager)
+            }
+        )
+
+        return remember { derivedStateOf { listener.isEnabled() } }
+    }
+
+    @Composable
+    private fun Lifecycle.ObserveState(
+        handleEvent: (Lifecycle.Event) -> Unit = {},
+        onDispose: () -> Unit = {}
+    ) {
+        DisposableEffect(this) {
+            val observer = LifecycleEventObserver { _, event ->
+                handleEvent(event)
+            }
+            [email protected](observer)
+            onDispose {
+                onDispose()
+                [email protected](observer)
+            }
+        }
+    }
+
+    private class Listener : AccessibilityStateChangeListener, TouchExplorationStateChangeListener {
+        private var accessibilityEnabled by mutableStateOf(false)
+        private var touchExplorationEnabled by mutableStateOf(false)
+
+        fun isEnabled() = accessibilityEnabled && touchExplorationEnabled
+
+        override fun onAccessibilityStateChanged(it: Boolean) {
+            accessibilityEnabled = it
+        }
+
+        override fun onTouchExplorationStateChanged(it: Boolean) {
+            touchExplorationEnabled = it
+        }
+
+        fun register(am: AccessibilityManager) {
+            accessibilityEnabled = am.isEnabled
+            touchExplorationEnabled = am.isTouchExplorationEnabled
+
+            am.addTouchExplorationStateChangeListener(this)
+            am.addAccessibilityStateChangeListener(this)
+        }
+
+        fun unregister(am: AccessibilityManager) {
+            am.removeTouchExplorationStateChangeListener(this)
+            am.removeAccessibilityStateChangeListener(this)
+        }
+    }
 }
 
 enum class FocusableElement12Hour(val index: Int) {
@@ -1202,4 +1171,4 @@
     YEAR(2),
     CONFIRM_BUTTON(3),
     NONE(-1)
-}
\ No newline at end of file
+}
diff --git a/wear/watchface/watchface/src/main/AndroidManifest.xml b/wear/watchface/watchface/src/main/AndroidManifest.xml
index a933d34..55eedab 100644
--- a/wear/watchface/watchface/src/main/AndroidManifest.xml
+++ b/wear/watchface/watchface/src/main/AndroidManifest.xml
@@ -32,6 +32,7 @@
     <service
         android:name="androidx.wear.watchface.control.WatchFaceControlService"
         android:enabled="@bool/watch_face_instance_service_enabled"
+        android:directBootAware="true"
         android:exported="true"
         android:permission="com.google.android.wearable.permission.BIND_WATCH_FACE_CONTROL">
       <meta-data android:name="androidx.wear.watchface.api_version"
diff --git a/webkit/webkit/src/main/java/androidx/webkit/DropDataContentProvider.java b/webkit/webkit/src/main/java/androidx/webkit/DropDataContentProvider.java
index 07acee1..e8e0d93 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/DropDataContentProvider.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/DropDataContentProvider.java
@@ -41,7 +41,7 @@
  *
  * <pre class="prettyprint">
  *  &lt;provider
- *             android:authorities="{{your-package}}.DropDataProvider"
+ *             android:authorities="&lt;your-package&gt;.DropDataProvider"
  *             android:name="androidx.webkit.DropDataContentProvider"
  *             android:exported="false"
  *             android:grantUriPermissions="true"/&gt;