[go: nahoru, domu]

InteractionState -> [Mutable]InteractionSource rework

This CL replaces InteractionState with [Mutable]InteractionSource - interfaces responsible for emitting / observing Interaction events. InteractionSource exposes interactions: Flow<Interaction>, which allows consumers to observe the ordered stream of Interactions and change how components appear accordingly.

This resolves a few issues with the existing InteractionState implementation:

- No handling for multiple sources of the same Interaction
For example, a compound component with two `clickable`s - if one `clickable` is pressed, then the other, then the first `clickable` is released, this would appear as though the entire InteractionState was not pressed.

- Lossy compression of events into state
InteractionState turns a stream events into a snapshot state at a given point in time. Complex components / indications such as Ripple care about the ordering of events, and trying to reconstruct ordering from a snapshot state is a bit messy and can lose information.

- Batched state writes
State<> is not a great fit for representing events as the name suggests - one of the reasons for this is that state writes are batched, so multiple changes (such as multiple fast presses) will be batched into one write. This means that we might skip showing ripples for presses if events happen too closely together.

- Lack of detailed information for events
For simple components, just knowing if the component is pressed or not can be enough to change how it appears, but for complicated components it can be important to know if a press was stopped / cancelled - this sort of information did not exist in InteractionState. Additionally metadata such as press position can be important, but there was no scalable way to support this. Now Interactions can just be unique instances with metadata, so Pressed() can contain a press position just as a property for consumers that need to know this information.

As well as the `interactions` Flow, simple extension functions on InteractionSource (collectIsDraggedAsState, collectIsFocusedAsState, collectIsPressedAsState) have been added for cases when components only care about the binary state of a particular interaction, and not the entire stream of events.

MutableInteractionSource exposes `emit()` and `tryEmit()` methods that allow emitting Interactions to the `interactions` Flow.

This CL also changes the existing Interactions to be classes, and adds further classes representing stop / cancel events for the initial events.

Bug: b/152525426
Fixes: b/171913923
Fixes: b/171710801
Fixes: b/174852378
Test: InteractionSourceTest
Test: updateApi
Relnote: "InteractionState has been replaced with [Mutable]InteractionSource - interfaces responsible for emitting / collecting Interaction events. Instead of passing `interactionState = remember { InteractionState() }` to components such as Button and Modifier.clickable(), use `interactionSource = remember { MutableInteractionSource() }`. Instead of: `Interaction.Pressed in interactionState` you should instead use the extension functions on InteractionSource, such as InteractionSource.collectIsPressedAsState(). For complex use cases you can use InteractionSource.interactions to observe the stream of Interactions. See the InteractionSource documentation and samples for more information."
Change-Id: I85965d0dba39d1740c097915d1d1a367eea2a78c
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
index b1cd642..2eb8910 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
@@ -22,7 +22,7 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
@@ -70,7 +70,7 @@
         modifier = Modifier.fillMaxSize().clickable(
             >
             indication = null,
-            interactionState = remember { InteractionState() }
+            interactionSource = remember { MutableInteractionSource() }
         )
     ) {
         width = size.width
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
index bbcd355..9202ca8 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
@@ -20,7 +20,7 @@
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.spring
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Box
@@ -48,7 +48,7 @@
     Box(
         Modifier.fillMaxSize().clickable(
             indication = null,
-            interactionState = remember { InteractionState() }
+            interactionSource = remember { MutableInteractionSource() }
         ) {
             enabled
                 .value = !enabled
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index d684cc2..9d001c1 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -33,9 +33,9 @@
 
   public final class ClickableKt {
     method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
     method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ClickableTextKt {
@@ -50,7 +50,7 @@
   }
 
   public final class FocusableKt {
-    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public final class ImageKt {
@@ -60,7 +60,7 @@
   }
 
   @androidx.compose.runtime.Stable public interface Indication {
-    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public interface IndicationInstance {
@@ -69,32 +69,7 @@
 
   public final class IndicationKt {
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.Indication> getLocalIndication();
-    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication);
-  }
-
-  public interface Interaction {
-  }
-
-  public static final class Interaction.Dragged implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Dragged INSTANCE;
-  }
-
-  public static final class Interaction.Focused implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Focused INSTANCE;
-  }
-
-  public static final class Interaction.Pressed implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Pressed INSTANCE;
-  }
-
-  @androidx.compose.runtime.Stable public final class InteractionState implements androidx.compose.runtime.State<java.util.Set<? extends androidx.compose.foundation.Interaction>> {
-    ctor public InteractionState();
-    method public void addInteraction-Jgxim6Q(androidx.compose.foundation.Interaction interaction, optional androidx.compose.ui.geometry.Offset? position);
-    method public operator boolean contains(androidx.compose.foundation.Interaction interaction);
-    method public java.util.Set<androidx.compose.foundation.Interaction> getValue();
-    method public androidx.compose.ui.geometry.Offset? interactionPositionFor-_m7T9-E(androidx.compose.foundation.Interaction interaction);
-    method public void removeInteraction(androidx.compose.foundation.Interaction interaction);
-    property public java.util.Set<androidx.compose.foundation.Interaction> value;
+    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.foundation.Indication? indication);
   }
 
   @kotlin.RequiresOptIn(message="This API is internal to library.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalFoundationApi {
@@ -127,13 +102,13 @@
     ctor public ScrollState(int initial);
     method public suspend Object? animateScrollTo(int value, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public float dispatchRawDelta(float delta);
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public int getMaxValue();
     method public int getValue();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollTo(int value, kotlin.coroutines.Continuation<? super java.lang.Float> p);
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final int maxValue;
     property public final int value;
@@ -174,7 +149,7 @@
 
   public final class DraggableKt {
     method public static androidx.compose.foundation.gestures.DraggableState DraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
-    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
+    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
     method @androidx.compose.runtime.Composable public static androidx.compose.foundation.gestures.DraggableState rememberDraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
   }
 
@@ -222,7 +197,7 @@
   }
 
   public final class ScrollableKt {
-    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public interface ScrollableState {
@@ -280,6 +255,91 @@
 
 }
 
+package androidx.compose.foundation.interaction {
+
+  public interface DragInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class DragInteraction.Cancel implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Cancel(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public static final class DragInteraction.Start implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Start();
+  }
+
+  public static final class DragInteraction.Stop implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Stop(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public final class DragInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsDraggedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface FocusInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class FocusInteraction.Focus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Focus();
+  }
+
+  public static final class FocusInteraction.Unfocus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Unfocus(androidx.compose.foundation.interaction.FocusInteraction.Focus focus);
+    method public androidx.compose.foundation.interaction.FocusInteraction.Focus getFocus();
+    property public final androidx.compose.foundation.interaction.FocusInteraction.Focus focus;
+  }
+
+  public final class FocusInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsFocusedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface Interaction {
+  }
+
+  @androidx.compose.runtime.Stable public interface InteractionSource {
+    method public kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> getInteractions();
+    property public abstract kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> interactions;
+  }
+
+  public final class InteractionSourceKt {
+    method public static androidx.compose.foundation.interaction.MutableInteractionSource MutableInteractionSource();
+  }
+
+  @androidx.compose.runtime.Stable public interface MutableInteractionSource extends androidx.compose.foundation.interaction.InteractionSource {
+    method public suspend Object? emit(androidx.compose.foundation.interaction.Interaction interaction, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public boolean tryEmit(androidx.compose.foundation.interaction.Interaction interaction);
+  }
+
+  public interface PressInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class PressInteraction.Cancel implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Cancel(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public static final class PressInteraction.Press implements androidx.compose.foundation.interaction.PressInteraction {
+    method public long getPressPosition-F1C5BW0();
+    property public final long pressPosition;
+  }
+
+  public static final class PressInteraction.Release implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Release(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public final class PressInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsPressedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+}
+
 package androidx.compose.foundation.lazy {
 
   public final class CachingItemContentFactoryKt {
@@ -371,14 +431,14 @@
     method public float dispatchRawDelta(float delta);
     method public int getFirstVisibleItemIndex();
     method public int getFirstVisibleItemScrollOffset();
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public androidx.compose.foundation.lazy.LazyListLayoutInfo getLayoutInfo();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToItem(int index, optional int scrollOffset, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     property public final int firstVisibleItemIndex;
     property public final int firstVisibleItemScrollOffset;
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final androidx.compose.foundation.lazy.LazyListLayoutInfo layoutInfo;
     field public static final androidx.compose.foundation.lazy.LazyListState.Companion Companion;
@@ -419,14 +479,14 @@
 
   public final class SelectableKt {
     method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ToggleableKt {
     method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
-    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
+    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
     method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
 }
@@ -538,8 +598,8 @@
   }
 
   public final class BasicTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
   }
 
   public final class BasicTextKt {
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index d684cc2..9d001c1 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -33,9 +33,9 @@
 
   public final class ClickableKt {
     method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
     method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ClickableTextKt {
@@ -50,7 +50,7 @@
   }
 
   public final class FocusableKt {
-    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public final class ImageKt {
@@ -60,7 +60,7 @@
   }
 
   @androidx.compose.runtime.Stable public interface Indication {
-    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public interface IndicationInstance {
@@ -69,32 +69,7 @@
 
   public final class IndicationKt {
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.Indication> getLocalIndication();
-    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication);
-  }
-
-  public interface Interaction {
-  }
-
-  public static final class Interaction.Dragged implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Dragged INSTANCE;
-  }
-
-  public static final class Interaction.Focused implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Focused INSTANCE;
-  }
-
-  public static final class Interaction.Pressed implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Pressed INSTANCE;
-  }
-
-  @androidx.compose.runtime.Stable public final class InteractionState implements androidx.compose.runtime.State<java.util.Set<? extends androidx.compose.foundation.Interaction>> {
-    ctor public InteractionState();
-    method public void addInteraction-Jgxim6Q(androidx.compose.foundation.Interaction interaction, optional androidx.compose.ui.geometry.Offset? position);
-    method public operator boolean contains(androidx.compose.foundation.Interaction interaction);
-    method public java.util.Set<androidx.compose.foundation.Interaction> getValue();
-    method public androidx.compose.ui.geometry.Offset? interactionPositionFor-_m7T9-E(androidx.compose.foundation.Interaction interaction);
-    method public void removeInteraction(androidx.compose.foundation.Interaction interaction);
-    property public java.util.Set<androidx.compose.foundation.Interaction> value;
+    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.foundation.Indication? indication);
   }
 
   @kotlin.RequiresOptIn(message="This API is internal to library.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalFoundationApi {
@@ -127,13 +102,13 @@
     ctor public ScrollState(int initial);
     method public suspend Object? animateScrollTo(int value, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public float dispatchRawDelta(float delta);
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public int getMaxValue();
     method public int getValue();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollTo(int value, kotlin.coroutines.Continuation<? super java.lang.Float> p);
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final int maxValue;
     property public final int value;
@@ -174,7 +149,7 @@
 
   public final class DraggableKt {
     method public static androidx.compose.foundation.gestures.DraggableState DraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
-    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
+    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
     method @androidx.compose.runtime.Composable public static androidx.compose.foundation.gestures.DraggableState rememberDraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
   }
 
@@ -222,7 +197,7 @@
   }
 
   public final class ScrollableKt {
-    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public interface ScrollableState {
@@ -280,6 +255,91 @@
 
 }
 
+package androidx.compose.foundation.interaction {
+
+  public interface DragInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class DragInteraction.Cancel implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Cancel(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public static final class DragInteraction.Start implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Start();
+  }
+
+  public static final class DragInteraction.Stop implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Stop(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public final class DragInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsDraggedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface FocusInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class FocusInteraction.Focus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Focus();
+  }
+
+  public static final class FocusInteraction.Unfocus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Unfocus(androidx.compose.foundation.interaction.FocusInteraction.Focus focus);
+    method public androidx.compose.foundation.interaction.FocusInteraction.Focus getFocus();
+    property public final androidx.compose.foundation.interaction.FocusInteraction.Focus focus;
+  }
+
+  public final class FocusInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsFocusedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface Interaction {
+  }
+
+  @androidx.compose.runtime.Stable public interface InteractionSource {
+    method public kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> getInteractions();
+    property public abstract kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> interactions;
+  }
+
+  public final class InteractionSourceKt {
+    method public static androidx.compose.foundation.interaction.MutableInteractionSource MutableInteractionSource();
+  }
+
+  @androidx.compose.runtime.Stable public interface MutableInteractionSource extends androidx.compose.foundation.interaction.InteractionSource {
+    method public suspend Object? emit(androidx.compose.foundation.interaction.Interaction interaction, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public boolean tryEmit(androidx.compose.foundation.interaction.Interaction interaction);
+  }
+
+  public interface PressInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class PressInteraction.Cancel implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Cancel(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public static final class PressInteraction.Press implements androidx.compose.foundation.interaction.PressInteraction {
+    method public long getPressPosition-F1C5BW0();
+    property public final long pressPosition;
+  }
+
+  public static final class PressInteraction.Release implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Release(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public final class PressInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsPressedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+}
+
 package androidx.compose.foundation.lazy {
 
   public final class CachingItemContentFactoryKt {
@@ -371,14 +431,14 @@
     method public float dispatchRawDelta(float delta);
     method public int getFirstVisibleItemIndex();
     method public int getFirstVisibleItemScrollOffset();
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public androidx.compose.foundation.lazy.LazyListLayoutInfo getLayoutInfo();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToItem(int index, optional int scrollOffset, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     property public final int firstVisibleItemIndex;
     property public final int firstVisibleItemScrollOffset;
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final androidx.compose.foundation.lazy.LazyListLayoutInfo layoutInfo;
     field public static final androidx.compose.foundation.lazy.LazyListState.Companion Companion;
@@ -419,14 +479,14 @@
 
   public final class SelectableKt {
     method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ToggleableKt {
     method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
-    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
+    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
     method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
 }
@@ -538,8 +598,8 @@
   }
 
   public final class BasicTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
   }
 
   public final class BasicTextKt {
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index d684cc2..9d001c1 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -33,9 +33,9 @@
 
   public final class ClickableKt {
     method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier clickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
     method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method @androidx.compose.foundation.ExperimentalFoundationApi public static androidx.compose.ui.Modifier combinedClickable(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional String? onClickLabel, optional androidx.compose.ui.semantics.Role? role, optional String? onLongClickLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onDoubleClick, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ClickableTextKt {
@@ -50,7 +50,7 @@
   }
 
   public final class FocusableKt {
-    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier focusable(androidx.compose.ui.Modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public final class ImageKt {
@@ -60,7 +60,7 @@
   }
 
   @androidx.compose.runtime.Stable public interface Indication {
-    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.IndicationInstance rememberUpdatedInstance(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public interface IndicationInstance {
@@ -69,32 +69,7 @@
 
   public final class IndicationKt {
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.compose.foundation.Indication> getLocalIndication();
-    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication);
-  }
-
-  public interface Interaction {
-  }
-
-  public static final class Interaction.Dragged implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Dragged INSTANCE;
-  }
-
-  public static final class Interaction.Focused implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Focused INSTANCE;
-  }
-
-  public static final class Interaction.Pressed implements androidx.compose.foundation.Interaction {
-    field public static final androidx.compose.foundation.Interaction.Pressed INSTANCE;
-  }
-
-  @androidx.compose.runtime.Stable public final class InteractionState implements androidx.compose.runtime.State<java.util.Set<? extends androidx.compose.foundation.Interaction>> {
-    ctor public InteractionState();
-    method public void addInteraction-Jgxim6Q(androidx.compose.foundation.Interaction interaction, optional androidx.compose.ui.geometry.Offset? position);
-    method public operator boolean contains(androidx.compose.foundation.Interaction interaction);
-    method public java.util.Set<androidx.compose.foundation.Interaction> getValue();
-    method public androidx.compose.ui.geometry.Offset? interactionPositionFor-_m7T9-E(androidx.compose.foundation.Interaction interaction);
-    method public void removeInteraction(androidx.compose.foundation.Interaction interaction);
-    property public java.util.Set<androidx.compose.foundation.Interaction> value;
+    method public static androidx.compose.ui.Modifier indication(androidx.compose.ui.Modifier, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.foundation.Indication? indication);
   }
 
   @kotlin.RequiresOptIn(message="This API is internal to library.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalFoundationApi {
@@ -127,13 +102,13 @@
     ctor public ScrollState(int initial);
     method public suspend Object? animateScrollTo(int value, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public float dispatchRawDelta(float delta);
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public int getMaxValue();
     method public int getValue();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollTo(int value, kotlin.coroutines.Continuation<? super java.lang.Float> p);
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final int maxValue;
     property public final int value;
@@ -174,7 +149,7 @@
 
   public final class DraggableKt {
     method public static androidx.compose.foundation.gestures.DraggableState DraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
-    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.InteractionState? interactionState, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
+    method public static androidx.compose.ui.Modifier draggable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.DraggableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional boolean startDragImmediately, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super androidx.compose.ui.geometry.Offset,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStarted, optional kotlin.jvm.functions.Function3<? super kotlinx.coroutines.CoroutineScope,? super java.lang.Float,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> onDragStopped, optional boolean reverseDirection);
     method @androidx.compose.runtime.Composable public static androidx.compose.foundation.gestures.DraggableState rememberDraggableState(kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onDelta);
   }
 
@@ -222,7 +197,7 @@
   }
 
   public final class ScrollableKt {
-    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.InteractionState? interactionState);
+    method public static androidx.compose.ui.Modifier scrollable(androidx.compose.ui.Modifier, androidx.compose.foundation.gestures.ScrollableState state, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.gestures.FlingBehavior? flingBehavior, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource);
   }
 
   public interface ScrollableState {
@@ -280,6 +255,91 @@
 
 }
 
+package androidx.compose.foundation.interaction {
+
+  public interface DragInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class DragInteraction.Cancel implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Cancel(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public static final class DragInteraction.Start implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Start();
+  }
+
+  public static final class DragInteraction.Stop implements androidx.compose.foundation.interaction.DragInteraction {
+    ctor public DragInteraction.Stop(androidx.compose.foundation.interaction.DragInteraction.Start start);
+    method public androidx.compose.foundation.interaction.DragInteraction.Start getStart();
+    property public final androidx.compose.foundation.interaction.DragInteraction.Start start;
+  }
+
+  public final class DragInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsDraggedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface FocusInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class FocusInteraction.Focus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Focus();
+  }
+
+  public static final class FocusInteraction.Unfocus implements androidx.compose.foundation.interaction.FocusInteraction {
+    ctor public FocusInteraction.Unfocus(androidx.compose.foundation.interaction.FocusInteraction.Focus focus);
+    method public androidx.compose.foundation.interaction.FocusInteraction.Focus getFocus();
+    property public final androidx.compose.foundation.interaction.FocusInteraction.Focus focus;
+  }
+
+  public final class FocusInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsFocusedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+  public interface Interaction {
+  }
+
+  @androidx.compose.runtime.Stable public interface InteractionSource {
+    method public kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> getInteractions();
+    property public abstract kotlinx.coroutines.flow.Flow<androidx.compose.foundation.interaction.Interaction> interactions;
+  }
+
+  public final class InteractionSourceKt {
+    method public static androidx.compose.foundation.interaction.MutableInteractionSource MutableInteractionSource();
+  }
+
+  @androidx.compose.runtime.Stable public interface MutableInteractionSource extends androidx.compose.foundation.interaction.InteractionSource {
+    method public suspend Object? emit(androidx.compose.foundation.interaction.Interaction interaction, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public boolean tryEmit(androidx.compose.foundation.interaction.Interaction interaction);
+  }
+
+  public interface PressInteraction extends androidx.compose.foundation.interaction.Interaction {
+  }
+
+  public static final class PressInteraction.Cancel implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Cancel(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public static final class PressInteraction.Press implements androidx.compose.foundation.interaction.PressInteraction {
+    method public long getPressPosition-F1C5BW0();
+    property public final long pressPosition;
+  }
+
+  public static final class PressInteraction.Release implements androidx.compose.foundation.interaction.PressInteraction {
+    ctor public PressInteraction.Release(androidx.compose.foundation.interaction.PressInteraction.Press press);
+    method public androidx.compose.foundation.interaction.PressInteraction.Press getPress();
+    property public final androidx.compose.foundation.interaction.PressInteraction.Press press;
+  }
+
+  public final class PressInteractionKt {
+    method @androidx.compose.runtime.Composable public static androidx.compose.runtime.State<java.lang.Boolean> collectIsPressedAsState(androidx.compose.foundation.interaction.InteractionSource);
+  }
+
+}
+
 package androidx.compose.foundation.lazy {
 
   public final class CachingItemContentFactoryKt {
@@ -371,14 +431,14 @@
     method public float dispatchRawDelta(float delta);
     method public int getFirstVisibleItemIndex();
     method public int getFirstVisibleItemScrollOffset();
-    method public androidx.compose.foundation.InteractionState getInteractionState();
+    method public androidx.compose.foundation.interaction.InteractionSource getInteractionSource();
     method public androidx.compose.foundation.lazy.LazyListLayoutInfo getLayoutInfo();
     method public boolean isScrollInProgress();
     method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToItem(int index, optional int scrollOffset, optional kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     property public final int firstVisibleItemIndex;
     property public final int firstVisibleItemScrollOffset;
-    property public final androidx.compose.foundation.InteractionState interactionState;
+    property public final androidx.compose.foundation.interaction.InteractionSource interactionSource;
     property public boolean isScrollInProgress;
     property public final androidx.compose.foundation.lazy.LazyListLayoutInfo layoutInfo;
     field public static final androidx.compose.foundation.lazy.LazyListState.Companion Companion;
@@ -419,14 +479,14 @@
 
   public final class SelectableKt {
     method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier selectable(androidx.compose.ui.Modifier, boolean selected, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
   public final class ToggleableKt {
     method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
-    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
+    method public static androidx.compose.ui.Modifier toggleable(androidx.compose.ui.Modifier, boolean value, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onValueChange);
     method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
-    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.InteractionState interactionState, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public static androidx.compose.ui.Modifier triStateToggleable(androidx.compose.ui.Modifier, androidx.compose.ui.state.ToggleableState state, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, androidx.compose.foundation.Indication? indication, optional boolean enabled, optional androidx.compose.ui.semantics.Role? role, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
   }
 
 }
@@ -538,8 +598,8 @@
   }
 
   public final class BasicTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
-    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
+    method @androidx.compose.runtime.Composable public static void BasicTextField(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 androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
   }
 
   public final class BasicTextKt {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
index 3d73cbf..90a8a00 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/FoundationDemos.kt
@@ -17,8 +17,8 @@
 package androidx.compose.foundation.demos
 
 import androidx.compose.foundation.samples.ControlledScrollableRowSample
-import androidx.compose.foundation.samples.MultipleInteractionStateSample
-import androidx.compose.foundation.samples.PriorityInteractionStateSample
+import androidx.compose.foundation.samples.InteractionSourceFlowSample
+import androidx.compose.foundation.samples.SimpleInteractionSourceSample
 import androidx.compose.foundation.samples.VerticalScrollExample
 import androidx.compose.integration.demos.common.ComposableDemo
 import androidx.compose.integration.demos.common.DemoCategory
@@ -31,10 +31,8 @@
         ComposableDemo("Controlled Scrollable Row") { ControlledScrollableRowSample() },
         ComposableDemo("Draw Modifiers") { DrawModifiersDemo() },
         DemoCategory("Lazy lists", LazyListDemos),
-        ComposableDemo("Priority InteractionState") { PriorityInteractionStateSample() },
-        ComposableDemo("Multiple-interaction InteractionState") {
-            MultipleInteractionStateSample()
-        },
+        ComposableDemo("Simple InteractionSource") { SimpleInteractionSourceSample() },
+        ComposableDemo("Flow InteractionSource") { InteractionSourceFlowSample() },
         DemoCategory("Suspending Gesture Detectors", CoroutineGestureDemos),
         ComposableDemo("NestedScroll") { NestedScrollDemo() },
     )
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt
index 666640ed..019446f 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/ListDemos.kt
@@ -22,12 +22,12 @@
 import androidx.compose.animation.core.calculateTargetValue
 import androidx.compose.animation.defaultDecayAnimationSpec
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Interaction
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.gestures.FlingBehavior
 import androidx.compose.foundation.gestures.ScrollScope
 import androidx.compose.foundation.gestures.animateScrollBy
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -231,7 +231,7 @@
                 fontSize = 20.sp
             )
             Text(
-                "Dragging: ${state.interactionState.contains(Interaction.Dragged)}, " +
+                "Dragging: ${state.interactionSource.collectIsDraggedAsState().value}, " +
                     "Flinging: ${state.isScrollInProgress}",
                 fontSize = 20.sp
             )
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
index 48bf8cd..ca905b4 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/ComposeVariousInputField.kt
@@ -16,8 +16,10 @@
 
 package androidx.compose.foundation.demos.text
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -240,8 +242,8 @@
             }
         }
         item {
-            TagLine(tag = "TextField InteractionState")
-            InteractionStateTextField()
+            TagLine(tag = "TextField MutableInteractionSource")
+            InteractionSourceTextField()
         }
     }
 }
@@ -289,21 +291,30 @@
 }
 
 @Composable
-private fun InteractionStateTextField() {
+private fun InteractionSourceTextField() {
     val state = rememberSaveable(stateSaver = TextFieldValue.Saver) {
         mutableStateOf(TextFieldValue())
     }
-    val interactionState = remember { InteractionState() }
+    val interactionSource = remember { MutableInteractionSource() }
 
     Column(demoTextFieldModifiers) {
-        Text("Pressed?: ${interactionState.contains(Interaction.Pressed)}", fontSize = fontSize4)
-        Text("Focused?: ${interactionState.contains(Interaction.Focused)}", fontSize = fontSize4)
-        Text("Dragged?: ${interactionState.contains(Interaction.Dragged)}", fontSize = fontSize4)
+        Text(
+            "Pressed?: ${interactionSource.collectIsPressedAsState().value}",
+            fontSize = fontSize4
+        )
+        Text(
+            "Focused?: ${interactionSource.collectIsFocusedAsState().value}",
+            fontSize = fontSize4
+        )
+        Text(
+            "Dragged?: ${interactionSource.collectIsDraggedAsState().value}",
+            fontSize = fontSize4
+        )
         BasicTextField(
             modifier = Modifier.fillMaxWidth(),
             value = state.value,
             singleLine = true,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
              state.value = it },
             textStyle = TextStyle(fontSize = fontSize8)
         )
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt
index 1024bb9..f5ab3bc 100644
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/FocusableSample.kt
@@ -17,9 +17,9 @@
 package androidx.compose.foundation.samples
 
 import androidx.annotation.Sampled
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.focusable
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
 import androidx.compose.foundation.layout.Column
 import androidx.compose.material.Button
 import androidx.compose.material.Text
@@ -34,11 +34,11 @@
 fun FocusableSample() {
     // initialize focus reference to be able to request focus programmatically
     val focusRequester = FocusRequester()
-    // interaction state to track changes of the component's interactions (like "focused")
-    val interactionState = remember { InteractionState() }
+    // MutableInteractionSource to track changes of the component's interactions (like "focused")
+    val interactionSource = remember { MutableInteractionSource() }
 
     // text below will change when we focus it via button click
-    val isFocused = interactionState.contains(Interaction.Focused)
+    val isFocused = interactionSource.collectIsFocusedAsState().value
     val text = if (isFocused) {
         "Focused! tap anywhere to free the focus"
     } else {
@@ -51,7 +51,7 @@
             modifier = Modifier
                 // add focusRequester modifier before the focusable (or even in the parent)
                 .focusRequester(focusRequester)
-                .focusable(interactionState = interactionState)
+                .focusable(interactionSource = interactionSource)
         )
         Button( focusRequester.requestFocus() }) {
             Text("Bring focus to the text above")
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt
index 0b37029..e96b066 100644
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/IndicationSamples.kt
@@ -17,7 +17,7 @@
 package androidx.compose.foundation.samples
 
 import androidx.annotation.Sampled
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.LocalIndication
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.indication
@@ -25,8 +25,8 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.padding
-import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.material.Text
+import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
@@ -35,13 +35,16 @@
 @Composable
 @Sampled
 fun IndicationSample() {
-    val interactionState = remember { InteractionState() }
+    val interactionSource = remember { MutableInteractionSource() }
     Column {
         Text(
             text = "Click me and my neighbour will indicate as well!",
             modifier = Modifier
-                // clickable will update interaction state and show ripple
-                .clickable(interactionState = interactionState, indication = rememberRipple()) {
+                // clickable will dispatch events using MutableInteractionSource and show ripple
+                .clickable(
+                    interactionSource = interactionSource,
+                    indication = rememberRipple()
+                ) {
                     /**do something */
                 }
                 .padding(10.dp)
@@ -51,8 +54,8 @@
             text = "I'm neighbour and I indicate when you click the other one",
             modifier = Modifier
                 // this element doesn't have a click, but will show default indication from the
-                // CompositionLocal as it accepts same interaction state
-                .indication(interactionState, LocalIndication.current)
+                // CompositionLocal as it accepts the same MutableInteractionSource
+                .indication(interactionSource, LocalIndication.current)
                 .padding(10.dp)
         )
     }
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionSourceSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionSourceSample.kt
new file mode 100644
index 0000000..4b8fb36
--- /dev/null
+++ b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionSourceSample.kt
@@ -0,0 +1,205 @@
+/*
+ * 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.compose.foundation.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.draggable
+import androidx.compose.foundation.gestures.rememberDraggableState
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.LocalTextStyle
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
+
+@Sampled
+@Composable
+fun SimpleInteractionSourceSample() {
+    // Hoist the MutableInteractionSource that we will provide to interactions
+    val interactionSource = remember { MutableInteractionSource() }
+
+    // Provide the MutableInteractionSource instances to the interactions we want to observe state
+    // changes for
+    val draggable = Modifier.draggable(
+        interactionSource = interactionSource,
+        orientation = Orientation.Horizontal,
+        state = rememberDraggableState { /* update some business state here */ }
+    )
+
+    val clickable = Modifier.clickable(
+        interactionSource = interactionSource,
+        indication = LocalIndication.current
+    ) { /* update some business state here */ }
+
+    // Observe changes to the binary state for these interactions
+    val isDragged by interactionSource.collectIsDraggedAsState()
+    val isPressed by interactionSource.collectIsPressedAsState()
+
+    // Use the state to change our UI
+    val (text, color) = when {
+        isDragged && isPressed -> "Dragged and pressed" to Color.Red
+        isDragged -> "Dragged" to Color.Green
+        isPressed -> "Pressed" to Color.Blue
+        // Default / baseline state
+        else -> "Drag me horizontally, or press me!" to Color.Black
+    }
+
+    Box(
+        Modifier
+            .fillMaxSize()
+            .wrapContentSize()
+            .size(width = 240.dp, height = 80.dp)
+    ) {
+        Box(
+            Modifier
+                .fillMaxSize()
+                .then(clickable)
+                .then(draggable)
+                .border(BorderStroke(3.dp, color))
+                .padding(3.dp)
+        ) {
+            Text(
+                text, style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
+                modifier = Modifier.fillMaxSize().wrapContentSize()
+            )
+        }
+    }
+}
+
+@Sampled
+@Composable
+fun InteractionSourceFlowSample() {
+    // Hoist the MutableInteractionSource that we will provide to interactions
+    val interactionSource = remember { MutableInteractionSource() }
+
+    // Provide the MutableInteractionSource instances to the interactions we want to observe state
+    // changes for
+    val draggable = Modifier.draggable(
+        interactionSource = interactionSource,
+        orientation = Orientation.Horizontal,
+        state = rememberDraggableState { /* update some business state here */ }
+    )
+
+    val clickable = Modifier.clickable(
+        interactionSource = interactionSource,
+        // This component is a compound component where part of it is clickable and part of it is
+        // draggable. As a result we want to show indication for the _whole_ component, and not
+        // just for clickable area. We set `null` indication here and provide an explicit
+        // Modifier.indication instance later that will draw indication for the whole component.
+        indication = null
+    ) { /* update some business state here */ }
+
+    // SnapshotStateList we will use to track incoming Interactions in the order they are emitted
+    val interactions = remember { mutableStateListOf<Interaction>() }
+
+    // Collect Interactions - if they are new, add them to `interactions`. If they represent stop /
+    // cancel events for existing Interactions, remove them from `interactions` so it will only
+    // contain currently active `interactions`.
+    LaunchedEffect(interactionSource) {
+        interactionSource.interactions.collect { interaction ->
+            when (interaction) {
+                is PressInteraction.Press -> interactions.add(interaction)
+                is PressInteraction.Release -> interactions.remove(interaction.press)
+                is PressInteraction.Cancel -> interactions.remove(interaction.press)
+                is DragInteraction.Start -> interactions.add(interaction)
+                is DragInteraction.Stop -> interactions.remove(interaction.start)
+                is DragInteraction.Cancel -> interactions.remove(interaction.start)
+            }
+        }
+    }
+
+    // Display some text based on the most recent Interaction stored in `interactions`
+    val text = when (interactions.lastOrNull()) {
+        is DragInteraction.Start -> "Dragged"
+        is PressInteraction.Press -> "Pressed"
+        else -> "No state"
+    }
+
+    Column(
+        Modifier
+            .fillMaxSize()
+            .wrapContentSize()
+    ) {
+        Row(
+            // Draw indication for the whole component, based on the Interactions dispatched by
+            // our hoisted MutableInteractionSource
+            Modifier.indication(
+                interactionSource = interactionSource,
+                indication = LocalIndication.current
+            )
+        ) {
+            Box(
+                Modifier
+                    .size(width = 240.dp, height = 80.dp)
+                    .then(clickable)
+                    .border(BorderStroke(3.dp, Color.Blue))
+                    .padding(3.dp)
+            ) {
+                val pressed = interactions.any { it is PressInteraction.Press }
+                Text(
+                    text = if (pressed) "Pressed" else "Not pressed",
+                    style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
+                    modifier = Modifier.fillMaxSize().wrapContentSize()
+                )
+            }
+            Box(
+                Modifier
+                    .size(width = 240.dp, height = 80.dp)
+                    .then(draggable)
+                    .border(BorderStroke(3.dp, Color.Red))
+                    .padding(3.dp)
+            ) {
+                val dragged = interactions.any { it is DragInteraction.Start }
+                Text(
+                    text = if (dragged) "Dragged" else "Not dragged",
+                    style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
+                    modifier = Modifier.fillMaxSize().wrapContentSize()
+                )
+            }
+        }
+        Text(
+            text = text,
+            style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
+            modifier = Modifier.fillMaxSize().wrapContentSize()
+        )
+    }
+}
diff --git a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionStateSample.kt b/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionStateSample.kt
deleted file mode 100644
index 63cdd2d..0000000
--- a/compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/InteractionStateSample.kt
+++ /dev/null
@@ -1,167 +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.compose.foundation.samples
-
-import androidx.annotation.Sampled
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
-import androidx.compose.foundation.LocalIndication
-import androidx.compose.foundation.border
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.gestures.draggable
-import androidx.compose.foundation.gestures.rememberDraggableState
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.material.LocalTextStyle
-import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-
-@Sampled
-@Composable
-fun PriorityInteractionStateSample() {
-    val interactionState = remember { InteractionState() }
-
-    val draggable = Modifier.draggable(
-        orientation = Orientation.Horizontal,
-        interactionState = interactionState,
-        state = rememberDraggableState { /* update some business state here */ }
-    )
-
-    // Use InteractionState to determine how this component should appear during transient UI states
-    // In this example we are using a 'priority' system, such that we ignore multiple states, and
-    // don't care about the most recent state - Dragged is more important than Pressed.
-    val (text, color) = when {
-        Interaction.Dragged in interactionState -> "Dragged" to Color.Red
-        Interaction.Pressed in interactionState -> "Pressed" to Color.Blue
-        // Default / baseline state
-        else -> "Drag me horizontally, or press me!" to Color.Black
-    }
-
-    Box(
-        Modifier
-            .fillMaxSize()
-            .wrapContentSize()
-            .size(width = 240.dp, height = 80.dp)
-    ) {
-        Box(
-            Modifier
-                .fillMaxSize()
-                .clickable(
-                    interactionState = interactionState,
-                    indication = LocalIndication.current
-                ) { /* do nothing */ }
-                .then(draggable)
-                .border(BorderStroke(3.dp, color))
-                .padding(3.dp)
-        ) {
-            Text(
-                text, style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
-                modifier = Modifier.fillMaxSize().wrapContentSize()
-            )
-        }
-    }
-}
-
-@Sampled
-@Composable
-fun MultipleInteractionStateSample() {
-    val interactionState = remember { InteractionState() }
-
-    val draggable = Modifier.draggable(
-        orientation = Orientation.Horizontal,
-        interactionState = interactionState,
-        state = rememberDraggableState { /* update some business state here */ }
-    )
-
-    val clickable = Modifier.clickable(
-        interactionState = interactionState,
-        indication = LocalIndication.current
-    ) {
-        /* update some business state here */
-    }
-
-    // In this example we have a complex component that can be in multiple states at the same time
-    // (both pressed and dragged, since different areas of the same component can be pressed and
-    // dragged at the same time), and we want to use only the most recent state to show the visual
-    // state of the component. This could be with a visual overlay, or similar. Note that the most
-    // recent state is the _last_ state added to interactionState, so we want to start from the end,
-    // hence we use `lastOrNull` and not `firstOrNull`.
-    val latestState = interactionState.value.lastOrNull {
-        // We only care about pressed and dragged states here, so ignore everything else
-        it is Interaction.Dragged || it is Interaction.Pressed
-    }
-
-    val text = when (latestState) {
-        Interaction.Dragged -> "Dragged"
-        Interaction.Pressed -> "Pressed"
-        else -> "No state"
-    }
-
-    Column(
-        Modifier
-            .fillMaxSize()
-            .wrapContentSize()
-    ) {
-        Row {
-            Box(
-                Modifier
-                    .size(width = 240.dp, height = 80.dp)
-                    .then(clickable)
-                    .border(BorderStroke(3.dp, Color.Blue))
-                    .padding(3.dp)
-            ) {
-                val pressed = Interaction.Pressed in interactionState
-                Text(
-                    text = if (pressed) "Pressed" else "Not pressed",
-                    style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
-                    modifier = Modifier.fillMaxSize().wrapContentSize()
-                )
-            }
-            Box(
-                Modifier
-                    .size(width = 240.dp, height = 80.dp)
-                    .then(draggable)
-                    .border(BorderStroke(3.dp, Color.Red))
-                    .padding(3.dp)
-            ) {
-                val dragged = Interaction.Dragged in interactionState
-                Text(
-                    text = if (dragged) "Dragged" else "Not dragged",
-                    style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
-                    modifier = Modifier.fillMaxSize().wrapContentSize()
-                )
-            }
-        }
-        Text(
-            text = text,
-            style = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
-            modifier = Modifier.fillMaxSize().wrapContentSize()
-        )
-    }
-}
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 79a2dc8..b53e3ce 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,11 +16,15 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.InspectableValue
@@ -49,6 +53,9 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -409,48 +416,65 @@
     }
 
     @Test
-    fun clickableTest_interactionState() {
-        val interactionState = InteractionState()
+    fun clickableTest_interactionSource() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 BasicText(
                     "ClickableText",
                     modifier = Modifier
                         .testTag("myClickable")
                         .combinedClickable(
-                            interactionState = interactionState,
+                            interactionSource = interactionSource,
                             indication = null
                         ) {}
                 )
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag("myClickable")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         rule.onNodeWithTag("myClickable")
             .performGesture { up() }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Release::class.java)
+            assertThat((interactions[1] as PressInteraction.Release).press)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
-    fun clickableTest_interactionState_resetWhenDisposed() {
-        val interactionState = InteractionState()
+    fun clickableTest_interactionSource_resetWhenDisposed() {
+        val interactionSource = MutableInteractionSource()
         var emitClickableText by mutableStateOf(true)
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitClickableText) {
                     BasicText(
@@ -458,7 +482,7 @@
                         modifier = Modifier
                             .testTag("myClickable")
                             .combinedClickable(
-                                interactionState = interactionState,
+                                interactionSource = interactionSource,
                                 indication = null
                             ) {}
                     )
@@ -466,15 +490,22 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag("myClickable")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         // Dispose clickable
@@ -483,7 +514,11 @@
         }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Cancel::class.java)
+            assertThat((interactions[1] as PressInteraction.Cancel).press)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -618,7 +653,7 @@
         rule.setContent {
             val modifier = Modifier.combinedClickable(
                 >
-                interactionState = remember { InteractionState() },
+                interactionSource = remember { MutableInteractionSource() },
                 indication = null
             ) as InspectableValue
             assertThat(modifier.nameFallback).isEqualTo("combinedClickable")
@@ -632,7 +667,7 @@
                 "onLongClick",
                 "onLongClickLabel",
                 "indication",
-                "interactionState"
+                "interactionSource"
             )
         }
     }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt
index 0fb987b..b83b957 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/DraggableTest.kt
@@ -23,12 +23,16 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
@@ -45,6 +49,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -322,18 +329,27 @@
     }
 
     @Test
-    fun draggable_interactionState() {
-        val interactionState = InteractionState()
+    fun draggable_interactionSource() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         setDraggableContent {
+            scope = rememberCoroutineScope()
             Modifier.draggable(
                 Orientation.Horizontal,
-                interactionState = interactionState
+                interactionSource = interactionSource
             ) {}
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag(draggableBoxTag)
@@ -343,7 +359,8 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Dragged)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
         }
 
         rule.onNodeWithTag(draggableBoxTag)
@@ -352,16 +369,23 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
+            assertThat(interactions[1]).isInstanceOf(DragInteraction.Stop::class.java)
+            assertThat((interactions[1] as DragInteraction.Stop).start)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
-    fun draggable_interactionState_resetWhenDisposed() {
-        val interactionState = InteractionState()
+    fun draggable_interactionSource_resetWhenDisposed() {
+        val interactionSource = MutableInteractionSource()
         var emitDraggableBox by mutableStateOf(true)
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitDraggableBox) {
                     Box(
@@ -370,15 +394,21 @@
                             .size(100.dp)
                             .draggable(
                                 orientation = Orientation.Horizontal,
-                                interactionState = interactionState
+                                interactionSource = interactionSource
                             ) {}
                     )
                 }
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag(draggableBoxTag)
@@ -388,7 +418,8 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Dragged)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
         }
 
         // Dispose draggable
@@ -397,7 +428,11 @@
         }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
+            assertThat(interactions[1]).isInstanceOf(DragInteraction.Cancel::class.java)
+            assertThat((interactions[1] as DragInteraction.Cancel).start)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -414,7 +449,7 @@
                 "orientation",
                 "enabled",
                 "reverseDirection",
-                "interactionState",
+                "interactionSource",
                 "startDragImmediately",
                 "onDragStarted",
                 "onDragStopped",
@@ -441,7 +476,7 @@
         orientation: Orientation,
         enabled: Boolean = true,
         reverseDirection: Boolean = false,
-        interactionState: InteractionState? = null,
+        interactionSource: MutableInteractionSource? = null,
         startDragImmediately: Boolean = false,
         onDragStarted: (startedPosition: Offset) -> Unit = {},
         onDragStopped: (velocity: Float) -> Unit = {},
@@ -452,7 +487,7 @@
             orientation = orientation,
             enabled = enabled,
             reverseDirection = reverseDirection,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             startDragImmediately = startDragImmediately,
              onDragStarted(it) },
              onDragStopped(it) },
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
index 0384749..05a1c5f 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/FocusableTest.kt
@@ -16,10 +16,14 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -39,6 +43,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -137,17 +144,21 @@
 
     @ExperimentalComposeUiApi
     @Test
-    fun focusableTest_interactionState() {
-        val interactionState = InteractionState()
+    fun focusableTest_interactionSource() {
+        val interactionSource = MutableInteractionSource()
         val (focusRequester, otherFocusRequester) = FocusRequester.createRefs()
+
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 BasicText(
                     "focusableText",
                     modifier = Modifier
                         .testTag(focusTag)
                         .focusRequester(focusRequester)
-                        .focusable(interactionState = interactionState)
+                        .focusable(interactionSource = interactionSource)
                 )
                 BasicText(
                     "otherFocusableText",
@@ -158,8 +169,14 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+            Truth.assertThat(interactions).isEmpty()
         }
 
         rule.runOnIdle {
@@ -167,7 +184,8 @@
         }
 
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).contains(Interaction.Focused)
+            Truth.assertThat(interactions).hasSize(1)
+            Truth.assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
         }
 
         rule.runOnIdle {
@@ -175,17 +193,25 @@
         }
 
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+            Truth.assertThat(interactions).hasSize(2)
+            Truth.assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
+            Truth.assertThat(interactions[1])
+                .isInstanceOf(FocusInteraction.Unfocus::class.java)
+            Truth.assertThat((interactions[1] as FocusInteraction.Unfocus).focus)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
-    fun focusableTest_interactionState_resetWhenDisposed() {
-        val interactionState = InteractionState()
+    fun focusableTest_interactionSource_resetWhenDisposed() {
+        val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
         var emitFocusableText by mutableStateOf(true)
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitFocusableText) {
                     BasicText(
@@ -193,14 +219,20 @@
                         modifier = Modifier
                             .testTag(focusTag)
                             .focusRequester(focusRequester)
-                            .focusable(interactionState = interactionState)
+                            .focusable(interactionSource = interactionSource)
                     )
                 }
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+            Truth.assertThat(interactions).isEmpty()
         }
 
         rule.runOnIdle {
@@ -208,7 +240,8 @@
         }
 
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).contains(Interaction.Focused)
+            Truth.assertThat(interactions).hasSize(1)
+            Truth.assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
         }
 
         // Dispose focusable, Interaction should be gone
@@ -217,7 +250,12 @@
         }
 
         rule.runOnIdle {
-            Truth.assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+            Truth.assertThat(interactions).hasSize(2)
+            Truth.assertThat(interactions.first()).isInstanceOf(FocusInteraction.Focus::class.java)
+            Truth.assertThat(interactions[1])
+                .isInstanceOf(FocusInteraction.Unfocus::class.java)
+            Truth.assertThat((interactions[1] as FocusInteraction.Unfocus).focus)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -230,7 +268,7 @@
             Truth.assertThat(modifier.inspectableElements.map { it.name }.asIterable())
                 .containsExactly(
                     "enabled",
-                    "interactionState"
+                    "interactionSource"
                 )
         }
     }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt
index f53d422..0887889 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/IndicationTest.kt
@@ -16,13 +16,17 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.remember
-import androidx.compose.ui.graphics.drawscope.ContentDrawScope
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
@@ -36,9 +40,11 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -66,39 +72,49 @@
 
     @Test
     fun indication_receivesInitialState() {
-        val state = InteractionState()
+        val dispatcher = MutableInteractionSource()
         val countDownLatch = CountDownLatch(1)
         val indication = makeIndication {
-            // just wait for initial draw with empty interaction
-            if (it.value.isEmpty()) {
-                countDownLatch.countDown()
-            }
+            countDownLatch.countDown()
         }
         rule.setContent {
-            Box(Modifier.testTag(testTag).size(100.dp).indication(state, indication))
+            Box(Modifier.testTag(testTag).size(100.dp).indication(dispatcher, indication))
         }
         assertThat(countDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
     }
 
     @Test
     fun indication_click_receivesStateUpdates() {
-        // indicaiton should be called 3 times: 0 indication, press, and after click 0 again
+        // indication should be called 3 times: 0 indication, press, and after click 0 again
         val countDownLatch = CountDownLatch(3)
+        val interactions = mutableStateListOf<Interaction>()
+
+        val interactionSource = MutableInteractionSource()
+
         val indication = makeIndication {
-            it.value // value read
+            interactions.lastOrNull() // value read
             countDownLatch.countDown()
         }
+
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box(
                 Modifier
                     .testTag(testTag)
                     .size(100.dp)
                     .clickable(
-                        interactionState = remember { InteractionState() },
+                        interactionSource = interactionSource,
                         indication = indication,
                     ) {}
             )
         }
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         assertThat(countDownLatch.count).isEqualTo(2)
         rule.onNodeWithTag(testTag)
             .assertExists()
@@ -116,75 +132,16 @@
         assertThat(countDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
     }
 
-    @Test
-    @Ignore("b/155466122: multitouch is not supported yet")
-    fun indication_multiplyPress_firstWins() {
-        var lastPosition: Offset? = null
-        val indication = makeIndication {
-            it.value // value read
-            lastPosition = it.interactionPositionFor(Interaction.Pressed)
-        }
-        rule.setContent {
-            Box(
-                Modifier
-                    .testTag(testTag)
-                    .size(100.dp)
-                    .clickable(
-                        interactionState = remember { InteractionState() },
-                        indication = indication
-                    ) { }
-            )
-        }
-        assertThat(lastPosition).isNull()
-        var position1: Offset? = null
-        rule.onNodeWithTag(testTag)
-            .assertExists()
-            .performGesture {
-                position1 = Offset(center.x, center.y + 20f)
-                // pointer 1, when we have multitouch
-                down(position1!!)
-            }
-        rule.runOnIdle {
-            assertThat(lastPosition).isEqualTo(position1!!)
-        }
-        rule.onNodeWithTag(testTag)
-            .assertExists()
-            .performGesture {
-                val position2 = Offset(center.x + 20f, center.y)
-                // pointer 2, when we have multitouch
-                down(position2)
-            }
-        // should be still position1
-        rule.runOnIdle {
-            assertThat(lastPosition).isEqualTo(position1!!)
-        }
-        rule.onNodeWithTag(testTag)
-            .assertExists()
-            .performGesture {
-                // pointer 1, when we have multitouch
-                up()
-            }
-        rule.runOnIdle {
-            assertThat(lastPosition).isNull()
-        }
-        rule.onNodeWithTag(testTag)
-            .assertExists()
-            .performGesture {
-                // pointer 2, when we have multitouch
-                up()
-            }
-    }
-
-    private fun makeIndication(onDraw: (InteractionState) -> Unit): Indication {
+    private fun makeIndication(onDraw: () -> Unit): Indication {
         return object : Indication {
             @Composable
             override fun rememberUpdatedInstance(
-                interactionState: InteractionState
+                interactionSource: InteractionSource
             ): IndicationInstance {
-                return remember(interactionState) {
+                return remember(interactionSource) {
                     object : IndicationInstance {
                         override fun ContentDrawScope.drawIndication() {
-                            onDraw(interactionState)
+                            onDraw()
                         }
                     }
                 }
@@ -194,16 +151,16 @@
 
     @Test
     fun testInspectorValue() {
-        val state = InteractionState()
-        val indication = makeIndication({})
+        val state = MutableInteractionSource()
+        val indication = makeIndication {}
         rule.setContent {
             val modifier = Modifier.indication(state, indication) as InspectableValue
             assertThat(modifier.nameFallback).isEqualTo("indication")
             assertThat(modifier.valueOverride).isNull()
             assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
                 "indication",
-                "interactionState"
+                "interactionSource"
             )
         }
     }
-}
\ No newline at end of file
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/InteractionSourceTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/InteractionSourceTest.kt
new file mode 100644
index 0000000..bd9609b
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/InteractionSourceTest.kt
@@ -0,0 +1,361 @@
+/*
+ * 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.compose.foundation
+
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
+import androidx.compose.runtime.State
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalFoundationApi
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class InteractionSourceTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    private object TestInteraction1 : Interaction
+    private object TestInteraction2 : Interaction
+    private object TestInteraction3 : Interaction
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun emittingInteractionsInOrder() {
+        val interactionSource = MutableInteractionSource()
+
+        val interactions = mutableListOf<Interaction>()
+
+        val scope = TestCoroutineScope()
+
+        scope.launch {
+            interactionSource.interactions.collect {
+                interactions.add(it)
+            }
+        }
+        scope.launch {
+            interactionSource.emit(TestInteraction1)
+            interactionSource.emit(TestInteraction2)
+
+            assertThat(interactions)
+                .containsExactlyElementsIn(
+                    listOf(TestInteraction1, TestInteraction2)
+                )
+                .inOrder()
+
+            interactionSource.emit(TestInteraction3)
+
+            assertThat(interactions)
+                .containsExactlyElementsIn(
+                    listOf(TestInteraction1, TestInteraction2, TestInteraction3)
+                )
+                .inOrder()
+        }
+    }
+
+    @Test
+    fun isDragged() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isDragged: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isDragged = interactionSource.collectIsDraggedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isFalse()
+        }
+
+        var dragStart: DragInteraction.Start? = null
+
+        scope!!.launch {
+            dragStart = DragInteraction.Start()
+            interactionSource.emit(dragStart!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(DragInteraction.Stop(dragStart!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isFalse()
+        }
+    }
+
+    @Test
+    fun isDragged_multipleDrags() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isDragged: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isDragged = interactionSource.collectIsDraggedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isFalse()
+        }
+
+        var dragStart: DragInteraction.Start? = null
+
+        scope!!.launch {
+            dragStart = DragInteraction.Start()
+            interactionSource.emit(dragStart!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isTrue()
+        }
+
+        var dragStart2: DragInteraction.Start? = null
+
+        scope!!.launch {
+            dragStart2 = DragInteraction.Start()
+            interactionSource.emit(dragStart2!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(DragInteraction.Stop(dragStart!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(DragInteraction.Cancel(dragStart2!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isDragged!!.value).isFalse()
+        }
+    }
+
+    @Test
+    fun isFocused() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isFocused: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isFocused = interactionSource.collectIsFocusedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isFalse()
+        }
+
+        var focus: FocusInteraction.Focus? = null
+
+        scope!!.launch {
+            focus = FocusInteraction.Focus()
+            interactionSource.emit(focus!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(FocusInteraction.Unfocus(focus!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isFalse()
+        }
+    }
+
+    @Test
+    fun isFocused_multipleFocuses() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isFocused: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isFocused = interactionSource.collectIsFocusedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isFalse()
+        }
+
+        var focus: FocusInteraction.Focus? = null
+
+        scope!!.launch {
+            focus = FocusInteraction.Focus()
+            interactionSource.emit(focus!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isTrue()
+        }
+
+        var focus2: FocusInteraction.Focus? = null
+
+        scope!!.launch {
+            focus2 = FocusInteraction.Focus()
+            interactionSource.emit(focus2!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(FocusInteraction.Unfocus(focus!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(FocusInteraction.Unfocus(focus2!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isFocused!!.value).isFalse()
+        }
+    }
+
+    @Test
+    fun isPressed() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isPressed: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isPressed = interactionSource.collectIsPressedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isFalse()
+        }
+
+        var press: PressInteraction.Press? = null
+
+        scope!!.launch {
+            press = PressInteraction.Press(Offset.Zero)
+            interactionSource.emit(press!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(PressInteraction.Release(press!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isFalse()
+        }
+    }
+
+    @Test
+    fun isPressed_multiplePresses() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+        var isPressed: State<Boolean>? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            isPressed = interactionSource.collectIsPressedAsState()
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isFalse()
+        }
+
+        var press: PressInteraction.Press? = null
+
+        scope!!.launch {
+            press = PressInteraction.Press(Offset.Zero)
+            interactionSource.emit(press!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isTrue()
+        }
+
+        var press2: PressInteraction.Press? = null
+
+        scope!!.launch {
+            press2 = PressInteraction.Press(Offset.Zero)
+            interactionSource.emit(press2!!)
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(PressInteraction.Release(press!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isTrue()
+        }
+
+        scope!!.launch {
+            interactionSource.emit(PressInteraction.Cancel(press2!!))
+        }
+
+        rule.runOnIdle {
+            assertThat(isPressed!!.value).isFalse()
+        }
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index fb74142..fef0896 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.testutils.advanceClockOnMainThreadMillis
 import androidx.compose.testutils.runBlockingWithManualClock
@@ -36,6 +37,9 @@
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.platform.testTag
@@ -55,6 +59,9 @@
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.yield
 import org.junit.After
@@ -742,8 +749,8 @@
 
     @Test
     @OptIn(ExperimentalTestApi::class)
-    fun scrollable_interactionState() = runBlocking {
-        val interactionState = InteractionState()
+    fun scrollable_interactionSource() = runBlocking {
+        val interactionSource = MutableInteractionSource()
         var total = 0f
         val controller = ScrollableState(
             consumeScrollDelta = {
@@ -752,16 +759,25 @@
             }
         )
 
+        var scope: CoroutineScope? = null
+
         setScrollableContent {
+            scope = rememberCoroutineScope()
             Modifier.scrollable(
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 orientation = Orientation.Horizontal,
                 state = controller
             )
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag(scrollableBoxTag)
@@ -771,7 +787,8 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Dragged)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
         }
 
         rule.onNodeWithTag(scrollableBoxTag)
@@ -780,14 +797,18 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
+            assertThat(interactions[1]).isInstanceOf(DragInteraction.Stop::class.java)
+            assertThat((interactions[1] as DragInteraction.Stop).start)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
     @OptIn(ExperimentalTestApi::class)
-    fun scrollable_interactionState_resetWhenDisposed() = runBlocking {
-        val interactionState = InteractionState()
+    fun scrollable_interactionSource_resetWhenDisposed() = runBlocking {
+        val interactionSource = MutableInteractionSource()
         var emitScrollableBox by mutableStateOf(true)
         var total = 0f
         val controller = ScrollableState(
@@ -797,7 +818,10 @@
             }
         )
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitScrollableBox) {
                     Box(
@@ -805,7 +829,7 @@
                             .testTag(scrollableBoxTag)
                             .size(100.dp)
                             .scrollable(
-                                interactionState = interactionState,
+                                interactionSource = interactionSource,
                                 orientation = Orientation.Horizontal,
                                 state = controller
                             )
@@ -814,8 +838,14 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithTag(scrollableBoxTag)
@@ -825,7 +855,8 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Dragged)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
         }
 
         // Dispose scrollable
@@ -834,7 +865,11 @@
         }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(DragInteraction.Start::class.java)
+            assertThat(interactions[1]).isInstanceOf(DragInteraction.Cancel::class.java)
+            assertThat((interactions[1] as DragInteraction.Cancel).start)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -853,7 +888,7 @@
                 "enabled",
                 "reverseDirection",
                 "flingBehavior",
-                "interactionState",
+                "interactionSource",
             )
         }
     }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt
index 6d35fc9b..2100042 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SelectableTest.kt
@@ -16,12 +16,16 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.selection.selectable
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.InspectableValue
@@ -44,6 +48,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -124,15 +131,18 @@
     }
 
     @Test
-    fun selectableTest_interactionState() {
-        val interactionState = InteractionState()
+    fun selectableTest_interactionSource() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 Box(
                     Modifier.selectable(
                         selected = true,
-                        interactionState = interactionState,
+                        interactionSource = interactionSource,
                         indication = null,
                         >
                     )
@@ -142,37 +152,51 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithText("SelectableText")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         rule.onNodeWithText("SelectableText")
             .performGesture { up() }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Release::class.java)
+            assertThat((interactions[1] as PressInteraction.Release).press)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
-    fun selectableTest_interactionState_resetWhenDisposed() {
-        val interactionState = InteractionState()
+    fun selectableTest_interactionSource_resetWhenDisposed() {
+        val interactionSource = MutableInteractionSource()
         var emitSelectableText by mutableStateOf(true)
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitSelectableText) {
                     Box(
                         Modifier.selectable(
                             selected = true,
-                            interactionState = interactionState,
+                            interactionSource = interactionSource,
                             indication = null,
                             >
                         )
@@ -183,15 +207,22 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithText("SelectableText")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         // Dispose selectable
@@ -200,7 +231,11 @@
         }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Cancel::class.java)
+            assertThat((interactions[1] as PressInteraction.Cancel).press)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -224,7 +259,7 @@
         rule.setContent {
             val modifier = Modifier.selectable(
                 false,
-                interactionState = remember { InteractionState() },
+                interactionSource = remember { MutableInteractionSource() },
                 indication = null
             ) {} as InspectableValue
             assertThat(modifier.nameFallback).isEqualTo("selectable")
@@ -233,7 +268,7 @@
                 "selected",
                 "enabled",
                 "role",
-                "interactionState",
+                "interactionSource",
                 "indication",
                 "onClick"
             )
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt
index 0e54518..096b95f 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ToggleableTest.kt
@@ -16,6 +16,9 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.selection.toggleable
@@ -24,6 +27,7 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.InspectableValue
@@ -50,6 +54,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -209,15 +216,18 @@
     }
 
     @Test
-    fun toggleableTest_interactionState() {
-        val interactionState = InteractionState()
+    fun toggleableTest_interactionSource() {
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 Box(
                     Modifier.toggleable(
                         value = true,
-                        interactionState = interactionState,
+                        interactionSource = interactionSource,
                         indication = null,
                         >
                     )
@@ -227,37 +237,51 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithText("ToggleableText")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         rule.onNodeWithText("ToggleableText")
             .performGesture { up() }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Release::class.java)
+            assertThat((interactions[1] as PressInteraction.Release).press)
+                .isEqualTo(interactions[0])
         }
     }
 
     @Test
-    fun toggleableTest_interactionState_resetWhenDisposed() {
-        val interactionState = InteractionState()
+    fun toggleableTest_interactionSource_resetWhenDisposed() {
+        val interactionSource = MutableInteractionSource()
         var emitToggleableText by mutableStateOf(true)
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Box {
                 if (emitToggleableText) {
                     Box(
                         Modifier.toggleable(
                             value = true,
-                            interactionState = interactionState,
+                            interactionSource = interactionSource,
                             indication = null,
                             >
                         )
@@ -268,15 +292,22 @@
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).isEmpty()
         }
 
         rule.onNodeWithText("ToggleableText")
             .performGesture { down(center) }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).contains(Interaction.Pressed)
+            assertThat(interactions).hasSize(1)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
         }
 
         // Dispose toggleable
@@ -285,7 +316,11 @@
         }
 
         rule.runOnIdle {
-            assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+            assertThat(interactions).hasSize(2)
+            assertThat(interactions.first()).isInstanceOf(PressInteraction.Press::class.java)
+            assertThat(interactions[1]).isInstanceOf(PressInteraction.Cancel::class.java)
+            assertThat((interactions[1] as PressInteraction.Cancel).press)
+                .isEqualTo(interactions[0])
         }
     }
 
@@ -310,7 +345,7 @@
             val modifier = Modifier.toggleable(
                 value = true,
                 >
-                interactionState = remember { InteractionState() },
+                interactionSource = remember { MutableInteractionSource() },
                 indication = null
             ) as InspectableValue
             assertThat(modifier.nameFallback).isEqualTo("toggleable")
@@ -320,7 +355,7 @@
                 "enabled",
                 "role",
                 "indication",
-                "interactionState",
+                "interactionSource",
                 "onValueChange",
             )
         }
@@ -347,7 +382,7 @@
         rule.setContent {
             val modifier = Modifier.triStateToggleable(
                 state = ToggleableState.On,
-                interactionState = remember { InteractionState() },
+                interactionSource = remember { MutableInteractionSource() },
                 indication = null,
                 >
             )
@@ -359,7 +394,7 @@
                 "enabled",
                 "role",
                 "indication",
-                "interactionState",
+                "interactionSource",
                 "onClick",
             )
         }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt
index afd2fa4..11c2173 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/TextFieldInteractionsTest.kt
@@ -16,12 +16,16 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
@@ -41,6 +45,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,185 +64,304 @@
     @Test
     fun coreTextField_interaction_pressed() {
         val state = mutableStateOf(TextFieldValue(""))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.testTag(testTag),
                 value = state.value,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
             }
-        assertThat(interactionState.value).contains(Interaction.Pressed)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<PressInteraction.Press>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 up()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<PressInteraction.Press>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<PressInteraction.Release>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_pressed_removedWhenCancelled() {
         val state = mutableStateOf(TextFieldValue(""))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.testTag(testTag),
                 value = state.value,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
             }
-        assertThat(interactionState.value).contains(Interaction.Pressed)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<PressInteraction.Press>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 cancel()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Pressed)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<PressInteraction.Press>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<PressInteraction.Cancel>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_focused() {
         val state = mutableStateOf(TextFieldValue(""))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
         val focusRequester = FocusRequester()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.testTag(testTag),
                 value = state.value,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
             Box(
                 modifier = Modifier.requiredSize(10.dp).focusRequester(focusRequester).focusable(),
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performClick()
-        assertThat(interactionState.value).contains(Interaction.Focused)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
+        }
         rule.runOnIdle {
             // request focus on the box so TextField will lose it
             focusRequester.requestFocus()
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Focused)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<FocusInteraction.Unfocus>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_horizontally_dragged() {
         val state = mutableStateOf(TextFieldValue("test ".repeat(100)))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.testTag(testTag),
                 value = state.value,
                 singleLine = true,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
                 moveBy(Offset(x = 100f, y = 0f))
             }
-        assertThat(interactionState.value).contains(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 up()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<DragInteraction.Stop>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_dragged_horizontally_cancelled() {
         val state = mutableStateOf(TextFieldValue("test ".repeat(100)))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.testTag(testTag),
                 value = state.value,
                 singleLine = true,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
                 moveBy(Offset(x = 100f, y = 0f))
             }
-        assertThat(interactionState.value).contains(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 cancel()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<DragInteraction.Stop>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_vertically_dragged() {
         val state = mutableStateOf(TextFieldValue("test\n".repeat(10)))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.requiredSize(50.dp).testTag(testTag),
                 value = state.value,
                 maxLines = 3,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
                 moveBy(Offset(x = 0f, y = 150f))
             }
-        assertThat(interactionState.value).contains(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 up()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<DragInteraction.Stop>()).hasSize(1)
+        }
     }
 
     @Test
     fun coreTextField_interaction_dragged_vertically_cancelled() {
         val state = mutableStateOf(TextFieldValue("test\n".repeat(10)))
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
         rule.setContent {
+            scope = rememberCoroutineScope()
             BasicTextField(
                 modifier = Modifier.requiredSize(50.dp).testTag(testTag),
                 value = state.value,
                 maxLines = 3,
                  state.value = it },
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 down(center)
                 moveBy(Offset(x = 0f, y = 150f))
             }
-        assertThat(interactionState.value).contains(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+        }
         rule.onNodeWithTag(testTag)
             .performGesture {
                 cancel()
             }
-        assertThat(interactionState.value).doesNotContain(Interaction.Dragged)
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<DragInteraction.Start>()).hasSize(1)
+            assertThat(interactions.filterIsInstance<DragInteraction.Stop>()).hasSize(1)
+        }
     }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt
index ddf60aa..93cd20a 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldScrollTest.kt
@@ -18,7 +18,7 @@
 
 import android.os.Build
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.ScrollState
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.Orientation
@@ -360,15 +360,15 @@
     @Test
     fun textFieldScrollable_testInspectorValue() {
         val position = TextFieldScrollerPosition(Orientation.Vertical, 10f)
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
         rule.setContent {
             val modifier =
-                Modifier.textFieldScrollable(position, interactionState) as InspectableValue
+                Modifier.textFieldScrollable(position, interactionSource) as InspectableValue
             assertThat(modifier.nameFallback).isEqualTo("textFieldScrollable")
             assertThat(modifier.valueOverride).isNull()
             assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
                 "scrollerPosition",
-                "interactionState",
+                "interactionSource",
                 "enabled"
             )
         }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
index 171467c..1867880 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldTest.kt
@@ -21,8 +21,9 @@
 
 import android.os.Build
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -41,6 +42,7 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.testutils.assertShape
@@ -104,6 +106,9 @@
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.times
 import com.nhaarman.mockitokotlin2.verify
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -667,8 +672,12 @@
 
     @Test
     fun decorationBox_clickable() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             Column {
                 BasicTextField(
                     value = "test",
@@ -683,13 +692,19 @@
                             it()
                         }
                     },
-                    interactionState = interactionState
+                    interactionSource = interactionSource
                 )
             }
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
         rule.runOnIdle {
-            assertThat(interactionState.contains(Interaction.Focused)).isFalse()
+            assertThat(interactions).isEmpty()
         }
 
         // click outside core text field area
@@ -699,7 +714,8 @@
             }
 
         rule.runOnIdle {
-            assertThat(interactionState.contains(Interaction.Focused)).isTrue()
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
         }
     }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
index 6051969..95c6335 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Clickable.kt
@@ -17,9 +17,13 @@
 package androidx.compose.foundation
 
 import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
@@ -33,6 +37,7 @@
 import androidx.compose.ui.semantics.onLongClick
 import androidx.compose.ui.semantics.role
 import androidx.compose.ui.semantics.semantics
+import kotlinx.coroutines.launch
 
 /**
  * Configure component to receive clicks via input or accessibility "click" event.
@@ -40,8 +45,8 @@
  * Add this modifier to the element to make it clickable within its bounds and show a default
  * indication when it's pressed.
  *
- * This version has no [InteractionState] or [Indication] parameters, default indication from
- * [LocalIndication] will be used. To specify [InteractionState] or [Indication], use another
+ * This version has no [MutableInteractionSource] or [Indication] parameters, default indication from
+ * [LocalIndication] will be used. To specify [MutableInteractionSource] or [Indication], use another
  * overload.
  *
  * If you need to support double click or long click alongside the single click, consider
@@ -76,7 +81,7 @@
         >
         role = role,
         indication = LocalIndication.current,
-        interactionState = remember { InteractionState() }
+        interactionSource = remember { MutableInteractionSource() }
     )
 }
 
@@ -91,9 +96,9 @@
  *
  * @sample androidx.compose.foundation.samples.ClickableSample
  *
- * @param interactionState [InteractionState] that will be updated when this Clickable is
- * pressed, using [Interaction.Pressed]. Only initial (first) press will be recorded and added to
- * [InteractionState]
+ * @param interactionSource [MutableInteractionSource] that will be used to dispatch
+ * [PressInteraction.Press] when this clickable is pressed. Only the initial (first) press will be
+ * recorded and dispatched with [MutableInteractionSource].
  * @param indication indication to be shown when modified element is pressed. Be default,
  * indication from [LocalIndication] will be used. Pass `null` to show no indication, or
  * current value from [LocalIndication] to show theme default
@@ -106,7 +111,7 @@
  */
 @Suppress("DEPRECATION")
 fun Modifier.clickable(
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     onClickLabel: String? = null,
@@ -114,21 +119,60 @@
     onClick: () -> Unit
 ) = composed(
     factory = {
+        val scope = rememberCoroutineScope()
+        val pressedInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
         val interactionUpdate =
             if (enabled) {
                 Modifier.pressIndicatorGestureFilter(
-                     interactionState.addInteraction(Interaction.Pressed, it) },
-                     interactionState.removeInteraction(Interaction.Pressed) },
-                     interactionState.removeInteraction(Interaction.Pressed) }
+                    >
+                        scope.launch {
+                            // Remove any old interactions if we didn't fire stop / cancel properly
+                            pressedInteraction.value?.let { oldValue ->
+                                val interaction = PressInteraction.Cancel(oldValue)
+                                interactionSource.emit(interaction)
+                                pressedInteraction.value = null
+                            }
+                            val interaction = PressInteraction.Press(it)
+                            interactionSource.emit(interaction)
+                            pressedInteraction.value = interaction
+                        }
+                    },
+                    >
+                        scope.launch {
+                            pressedInteraction.value?.let {
+                                val interaction = PressInteraction.Release(it)
+                                interactionSource.emit(interaction)
+                                pressedInteraction.value = null
+                            }
+                        }
+                    },
+                    >
+                        scope.launch {
+                            pressedInteraction.value?.let {
+                                val interaction = PressInteraction.Cancel(it)
+                                interactionSource.emit(interaction)
+                                pressedInteraction.value = null
+                            }
+                        }
+                    }
                 )
             } else {
                 Modifier
             }
         val tap = if (enabled) tapGestureFilter( onClick() }) else Modifier
+        DisposableEffect(interactionSource) {
+            onDispose {
+                pressedInteraction.value?.let { oldValue ->
+                    val interaction = PressInteraction.Cancel(oldValue)
+                    interactionSource.tryEmit(interaction)
+                    pressedInteraction.value = null
+                }
+            }
+        }
         Modifier
             .genericClickableWithoutGesture(
                 gestureModifiers = Modifier.then(interactionUpdate).then(tap),
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = indication,
                 enabled = enabled,
                 >
@@ -145,7 +189,7 @@
         properties["role"] = role
         properties["onClick"] = onClick
         properties["indication"] = indication
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
     }
 )
 
@@ -157,9 +201,9 @@
  *
  * If you need only click handling, and no double or long clicks, consider using [clickable]
  *
- * This version has no [InteractionState] or [Indication] parameters, default indication from
- * [LocalIndication] will be used. To specify [InteractionState] or [Indication], use another
- * overload.
+ * This version has no [MutableInteractionSource] or [Indication] parameters, default indication
+ * from [LocalIndication] will be used. To specify [MutableInteractionSource] or [Indication],
+ * use another overload.
  *
  * @sample androidx.compose.foundation.samples.ClickableSample
  *
@@ -203,7 +247,7 @@
         >
         role = role,
         indication = LocalIndication.current,
-        interactionState = remember { InteractionState() }
+        interactionSource = remember { MutableInteractionSource() }
     )
 }
 
@@ -219,9 +263,9 @@
  *
  * @sample androidx.compose.foundation.samples.ClickableSample
  *
- * @param interactionState [InteractionState] that will be updated when this Clickable is
- * pressed, using [Interaction.Pressed]. Only initial (first) press will be recorded and added to
- * [InteractionState]
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [PressInteraction.Press] when this clickable is pressed. Only the initial (first) press will be
+ * recorded and emitted with [MutableInteractionSource].
  * @param indication indication to be shown when modified element is pressed. Be default,
  * indication from [LocalIndication] will be used. Pass `null` to show no indication, or
  * current value from [LocalIndication] to show theme default
@@ -237,7 +281,7 @@
  */
 @ExperimentalFoundationApi
 fun Modifier.combinedClickable(
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     onClickLabel: String? = null,
@@ -248,8 +292,10 @@
     onClick: () -> Unit
 ) = composed(
     factory = {
+        val scope = rememberCoroutineScope()
         val >
-        val interactionStateState = rememberUpdatedState(interactionState)
+        val interactionSourceState = rememberUpdatedState(interactionSource)
+        val pressedInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
         val gesture = if (enabled) {
             Modifier.pointerInput(onDoubleClick, onLongClick) {
                 detectTapGestures(
@@ -264,9 +310,25 @@
                         null
                     },
                     >
-                        interactionStateState.value.addInteraction(Interaction.Pressed, it)
+                        scope.launch {
+                            // Remove any old interactions if we didn't fire stop / cancel properly
+                            pressedInteraction.value?.let { oldValue ->
+                                val interaction = PressInteraction.Cancel(oldValue)
+                                interactionSourceState.value.emit(interaction)
+                                pressedInteraction.value = null
+                            }
+                            val interaction = PressInteraction.Press(it)
+                            interactionSourceState.value.emit(interaction)
+                            pressedInteraction.value = interaction
+                        }
                         tryAwaitRelease()
-                        interactionStateState.value.removeInteraction(Interaction.Pressed)
+                        scope.launch {
+                            pressedInteraction.value?.let { oldValue ->
+                                val interaction = PressInteraction.Release(oldValue)
+                                interactionSourceState.value.emit(interaction)
+                                pressedInteraction.value = null
+                            }
+                        }
                     },
                      onClickState.value.invoke() }
                 )
@@ -274,10 +336,21 @@
         } else {
             Modifier
         }
+        DisposableEffect(interactionSource) {
+            onDispose {
+                scope.launch {
+                    pressedInteraction.value?.let { oldValue ->
+                        val interaction = PressInteraction.Cancel(oldValue)
+                        interactionSourceState.value.emit(interaction)
+                        pressedInteraction.value = null
+                    }
+                }
+            }
+        }
         Modifier
             .genericClickableWithoutGesture(
                 gestureModifiers = gesture,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = indication,
                 enabled = enabled,
                 >
@@ -297,7 +370,7 @@
         properties["onLongClick"] = onLongClick
         properties["onLongClickLabel"] = onLongClickLabel
         properties["indication"] = indication
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
     }
 )
 
@@ -305,7 +378,7 @@
 @Suppress("ComposableModifierFactory")
 internal fun Modifier.genericClickableWithoutGesture(
     gestureModifiers: Modifier,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     onClickLabel: String? = null,
@@ -327,13 +400,8 @@
             disabled()
         }
     }
-    DisposableEffect(interactionState) {
-        onDispose {
-            interactionState.removeInteraction(Interaction.Pressed)
-        }
-    }
     return this
         .then(semanticModifier)
-        .indication(interactionState, indication)
+        .indication(interactionSource, indication)
         .then(gestureModifiers)
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt
index 26ee83c..71f3598 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Focusable.kt
@@ -16,10 +16,13 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
@@ -29,6 +32,7 @@
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.semantics.focused
 import androidx.compose.ui.semantics.semantics
+import kotlinx.coroutines.launch
 
 /**
  * Configure component to be focusable via focus system or accessibility "focus" event.
@@ -38,28 +42,40 @@
  * @sample androidx.compose.foundation.samples.FocusableSample
  *
  * @param enabled Controls the enabled state. When `false`, element won't participate in the focus
- * @param interactionState [InteractionState] that will be updated to contain [Interaction.Focused]
- * when this focusable is focused
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [FocusInteraction.Focus] when this element is being focused.
  */
 fun Modifier.focusable(
     enabled: Boolean = true,
-    interactionState: InteractionState? = null,
+    interactionSource: MutableInteractionSource? = null,
 ) = composed(
     inspectorInfo = debugInspectorInfo {
         name = "focusable"
         properties["enabled"] = enabled
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
     }
 ) {
+    val scope = rememberCoroutineScope()
+    val focusedInteraction = remember { mutableStateOf<FocusInteraction.Focus?>(null) }
     var isFocused by remember { mutableStateOf(false) }
-    DisposableEffect(Unit) {
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState?.removeInteraction(Interaction.Focused)
+            focusedInteraction.value?.let { oldValue ->
+                val interaction = FocusInteraction.Unfocus(oldValue)
+                interactionSource?.tryEmit(interaction)
+                focusedInteraction.value = null
+            }
         }
     }
     DisposableEffect(enabled) {
         if (!enabled) {
-            interactionState?.removeInteraction(Interaction.Focused)
+            scope.launch {
+                focusedInteraction.value?.let { oldValue ->
+                    val interaction = FocusInteraction.Unfocus(oldValue)
+                    interactionSource?.emit(interaction)
+                    focusedInteraction.value = null
+                }
+            }
         }
         onDispose { }
     }
@@ -72,9 +88,24 @@
             .onFocusChanged {
                 isFocused = it.isFocused
                 if (isFocused) {
-                    interactionState?.addInteraction(Interaction.Focused)
+                    scope.launch {
+                        focusedInteraction.value?.let { oldValue ->
+                            val interaction = FocusInteraction.Unfocus(oldValue)
+                            interactionSource?.emit(interaction)
+                            focusedInteraction.value = null
+                        }
+                        val interaction = FocusInteraction.Focus()
+                        interactionSource?.emit(interaction)
+                        focusedInteraction.value = interaction
+                    }
                 } else {
-                    interactionState?.removeInteraction(Interaction.Focused)
+                    scope.launch {
+                        focusedInteraction.value?.let { oldValue ->
+                            val interaction = FocusInteraction.Unfocus(oldValue)
+                            interactionSource?.emit(interaction)
+                            focusedInteraction.value = null
+                        }
+                    }
                 }
             }
             .focusModifier()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt
index a694453..61f30c1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Indication.kt
@@ -16,8 +16,11 @@
 
 package androidx.compose.foundation
 
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.collectIsPressedAsState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
@@ -43,21 +46,22 @@
 interface Indication {
 
     /**
-     * [remember]s a new [IndicationInstance], and updates its state when [interactionState]
-     * changes. Typically this will be called by [indication], so one [IndicationInstance] will be
-     * used for one component that draws [Indication], such as a button.
+     * [remember]s a new [IndicationInstance], and updates its state based on [Interaction]s
+     * emitted via [interactionSource] . Typically this will be called by [indication],
+     * so one [IndicationInstance] will be used for one component that draws [Indication], such
+     * as a button.
      *
-     * Implementations of this function should observe state changes inside [interactionState],
-     * using them to launch animations / state changes inside [IndicationInstance] that will then
-     * be reflected inside [IndicationInstance.drawIndication].
+     * Implementations of this function should observe [Interaction]s using [interactionSource],
+     * using them to launch animations / state changes inside [IndicationInstance] that will
+     * then be reflected inside [IndicationInstance.drawIndication].
      *
-     * @param interactionState the [InteractionState] containing the current interactions the
-     * returned [IndicationInstance] should represent
-     * @return an [IndicationInstance] that represents the current interactions present in
-     * [interactionState]
+     * @param interactionSource the [InteractionSource] representing the stream of
+     * [Interaction]s the returned [IndicationInstance] should represent
+     * @return an [IndicationInstance] that represents the stream of [Interaction]s emitted by
+     * [interactionSource]
      */
     @Composable
-    fun rememberUpdatedInstance(interactionState: InteractionState): IndicationInstance
+    fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance
 }
 
 /**
@@ -89,19 +93,19 @@
  *
  * @sample androidx.compose.foundation.samples.IndicationSample
  *
- * @param interactionState [InteractionState] that will be used by [indication] to draw visual
- * effects - this [InteractionState] represents the combined state of all interactions currently
- * present on this component.
+ * @param interactionSource [InteractionSource] that will be used by [indication] to draw
+ * visual effects - this [InteractionSource] represents the stream of [Interaction]s for this
+ * component.
  * @param indication [Indication] used to draw visual effects. If `null`, no visual effects will
  * be shown for this component.
  */
 fun Modifier.indication(
-    interactionState: InteractionState,
+    interactionSource: InteractionSource,
     indication: Indication?
 ) = composed(
     factory = {
         val resolvedIndication = indication ?: NoIndication
-        val instance = resolvedIndication.rememberUpdatedInstance(interactionState)
+        val instance = resolvedIndication.rememberUpdatedInstance(interactionSource)
         remember(instance) {
             IndicationModifier(instance)
         }
@@ -109,7 +113,7 @@
     inspectorInfo = debugInspectorInfo {
         name = "indication"
         properties["indication"] = indication
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
     }
 )
 
@@ -132,7 +136,7 @@
     }
 
     @Composable
-    override fun rememberUpdatedInstance(interactionState: InteractionState): IndicationInstance {
+    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
         return NoIndicationInstance
     }
 }
@@ -143,19 +147,22 @@
 private object DefaultDebugIndication : Indication {
 
     private class DefaultDebugIndicationInstance(
-        private val interactionState: InteractionState
+        private val isPressed: State<Boolean>
     ) : IndicationInstance {
         override fun ContentDrawScope.drawIndication() {
             drawContent()
-            if (interactionState.contains(Interaction.Pressed)) {
+            if (isPressed.value) {
                 drawRect(color = Color.Black.copy(alpha = 0.3f), size = size)
             }
         }
     }
 
     @Composable
-    override fun rememberUpdatedInstance(interactionState: InteractionState): IndicationInstance {
-        return remember(interactionState) { DefaultDebugIndicationInstance(interactionState) }
+    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
+        val isPressed = interactionSource.collectIsPressedAsState()
+        return remember(interactionSource) {
+            DefaultDebugIndicationInstance(isPressed)
+        }
     }
 }
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Interaction.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Interaction.kt
deleted file mode 100644
index 8f4b9b6..0000000
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Interaction.kt
+++ /dev/null
@@ -1,56 +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.compose.foundation
-
-/**
- * An Interaction represents transient UI state for a component, typically separate from the
- * actual 'business' state that a component may control. For example, a button typically fires an
- * `onClick` callback when the button is pressed and released, but it will still want to show
- * that it is being pressed before this callback is fired. This transient state is represented by
- * an Interaction, in this case [Pressed]. Using Interactions allows you to build
- * components that respond to these transient, component-owned state changes.
- *
- * The current interactions present on a given component are typically represented with an
- * [InteractionState]. See [InteractionState] for more information on consuming [Interaction]s,
- * and associated sample usage.
- */
-interface Interaction {
-    /**
-     * An interaction corresponding to a dragged state on a component.
-     *
-     * See [draggable][androidx.compose.foundation.gestures.draggable]
-     */
-    object Dragged : Interaction
-
-    /**
-     * An interaction corresponding to a pressed state on a component.
-     *
-     * See [clickable]
-     */
-    object Pressed : Interaction
-
-    /**
-     * An interaction corresponding to a focused state on a component.
-     *
-     * See [focusable]
-     */
-    object Focused : Interaction
-
-    /* TODO: b/152525426 add these states
-    object Hovered : Interaction
-    */
-}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/InteractionState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/InteractionState.kt
deleted file mode 100644
index 6e188f5..0000000
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/InteractionState.kt
+++ /dev/null
@@ -1,100 +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.compose.foundation
-
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.geometry.Offset
-
-/**
- * InteractionState represents a [Set] of [Interaction]s present on a given component. This
- * allows you to build higher level components comprised of lower level interactions such as
- * [clickable] and [androidx.compose.foundation.gestures.draggable], and react to [Interaction]
- * changes driven by these components in one place. For [Interaction]s with an associated
- * position, such as [Interaction.Pressed], you can retrieve this position by using
- * [interactionPositionFor].
- *
- * Creating an [InteractionState] and passing it to these lower level interactions will cause a
- * recomposition when there are changes to the state of [Interaction], such as when a [clickable]
- * becomes [Interaction.Pressed].
- *
- * For cases when you are only interested in one [Interaction], or you have a priority for cases
- * when multiple [Interaction]s are present, you can use [contains], such as in the following
- * example:
- *
- * @sample androidx.compose.foundation.samples.PriorityInteractionStateSample
- *
- * Often it is important to respond to the most recently added [Interaction], as this corresponds
- * to the user's most recent interaction with a component. To enable such cases, [value] is
- * guaranteed to have its ordering preserved, with the most recent [Interaction] added to the end.
- * As a result, you can simply iterate / filter [value] from the end, until you find an
- * [Interaction] you are interested in, such as in the following example:
- *
- * @sample androidx.compose.foundation.samples.MultipleInteractionStateSample
- */
-@Stable
-class InteractionState : State<Set<Interaction>> {
-
-    private var map: Map<Interaction, Offset?> by mutableStateOf(emptyMap())
-
-    /**
-     * The [Set] containing all [Interaction]s present in this [InteractionState]. Note that this
-     * set is ordered, and the most recently added [Interaction] will be the last element in the
-     * set. For representing the most recent [Interaction] in a component, you should iterate over
-     * the set in reversed order, until you find an [Interaction] that you are interested in.
-     */
-    override val value: Set<Interaction>
-        get() = map.keys
-
-    /**
-     * Adds the provided [interaction] to this InteractionState.
-     * Since InteractionState represents a [Set], duplicate [interaction]s will not be added, and
-     * hence will not cause a recomposition.
-     *
-     * @param interaction interaction to add
-     * @param position position at which the interaction occurred, if relevant. For example, for
-     * [Interaction.Pressed], this will be the position of the pointer input that triggered the
-     * pressed state.
-     */
-    fun addInteraction(interaction: Interaction, position: Offset? = null) {
-        if (interaction !in this) map = map + (interaction to position)
-    }
-
-    /**
-     * Removes the provided [interaction], if it is present, from this InteractionState.
-     */
-    fun removeInteraction(interaction: Interaction) {
-        if (interaction in this) map = map - interaction
-    }
-
-    /**
-     * Returns the position for a particular [Interaction], if there is a position associated
-     * with the interaction.
-     *
-     * @return position associated with the interaction, or `null` if the interaction is not
-     * present in this state, or there is no associated position with the given interaction.
-     */
-    fun interactionPositionFor(interaction: Interaction): Offset? = map[interaction]
-
-    /**
-     * @return whether the provided [interaction] exists inside this InteractionState.
-     */
-    operator fun contains(interaction: Interaction): Boolean = map.contains(interaction)
-}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 07861ad..9bf1b53 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -26,6 +26,8 @@
 import androidx.compose.foundation.gestures.animateScrollBy
 import androidx.compose.foundation.gestures.scrollBy
 import androidx.compose.foundation.gestures.scrollable
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
@@ -106,11 +108,13 @@
         }
 
     /**
-     * [InteractionState] that will be updated when the element with this state is being scrolled
-     * by dragging, using [Interaction.Dragged]. If you want to know whether the fling (or smooth
-     * scroll) is in progress, use [ScrollState.isScrollInProgress].
+     * [InteractionSource] that will be used to dispatch drag events when this
+     * list is being dragged. If you want to know whether the fling (or smooth scroll) is in
+     * progress, use [isScrollInProgress].
      */
-    val interactionState: InteractionState = InteractionState()
+    val interactionSource: InteractionSource get() = internalInteractionSource
+
+    internal val internalInteractionSource: MutableInteractionSource = MutableInteractionSource()
 
     private var _maxValueState = mutableStateOf(Int.MAX_VALUE, structuralEqualityPolicy())
 
@@ -283,7 +287,7 @@
             // if rtl and horizontal, do not reverse to make it right-to-left
             reverseDirection = if (!isVertical && isRtl) reverseScrolling else !reverseScrolling,
             enabled = isScrollable,
-            interactionState = state.interactionState,
+            interactionSource = state.internalInteractionSource,
             flingBehavior = flingBehavior,
             state = state
         )
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
index d8dab8c..67e0d67 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Draggable.kt
@@ -16,13 +16,15 @@
 
 package androidx.compose.foundation.gestures
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.MutatePriority
 import androidx.compose.foundation.MutatorMutex
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Modifier
@@ -37,6 +39,7 @@
 import androidx.compose.ui.platform.debugInspectorInfo
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
 import kotlin.coroutines.cancellation.CancellationException
 import kotlin.math.sign
 
@@ -141,8 +144,8 @@
  * interpreted by the user land logic.
  * @param orientation orientation of the drag
  * @param enabled whether or not drag is enabled
- * @param interactionState [InteractionState] that will be updated when this draggable is
- * being dragged, using [Interaction.Dragged].
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [DragInteraction.Start] when this draggable is being dragged.
  * @param startDragImmediately when set to true, draggable will start dragging immediately and
  * prevent other gesture detectors from reacting to "down" events (in order to block composed
  * press-based gestures).  This is intended to allow end users to "catch" an animating widget by
@@ -160,7 +163,7 @@
     state: DraggableState,
     orientation: Orientation,
     enabled: Boolean = true,
-    interactionState: InteractionState? = null,
+    interactionSource: MutableInteractionSource? = null,
     startDragImmediately: Boolean = false,
     onDragStarted: suspend CoroutineScope.(startedPosition: Offset) -> Unit = {},
     onDragStopped: suspend CoroutineScope.(velocity: Float) -> Unit = {},
@@ -171,23 +174,27 @@
         properties["orientation"] = orientation
         properties["enabled"] = enabled
         properties["reverseDirection"] = reverseDirection
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["startDragImmediately"] = startDragImmediately
         properties["onDragStarted"] = onDragStarted
         properties["onDragStopped"] = onDragStopped
         properties["state"] = state
     }
 ) {
-    DisposableEffect(interactionState) {
+    val draggedInteraction = remember { mutableStateOf<DragInteraction.Start?>(null) }
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState?.removeInteraction(Interaction.Dragged)
+            draggedInteraction.value?.let { interaction ->
+                interactionSource?.tryEmit(DragInteraction.Cancel(interaction))
+                draggedInteraction.value = null
+            }
         }
     }
     val orientationState = rememberUpdatedState(orientation)
     val enabledState = rememberUpdatedState(enabled)
     val reverseDirectionState = rememberUpdatedState(reverseDirection)
     val startImmediatelyState = rememberUpdatedState(startDragImmediately)
-    val interactionStateState = rememberUpdatedState(interactionState)
+    val interactionSourceState = rememberUpdatedState(interactionSource)
     val >
     val updatedDraggableState = rememberUpdatedState(state)
     val >
@@ -196,7 +203,8 @@
             dragForEachGesture(
                 orientation = orientationState,
                 enabled = enabledState,
-                interactionState = interactionStateState,
+                interactionSource = interactionSourceState,
+                dragStartInteraction = draggedInteraction,
                 reverseDirection = reverseDirectionState,
                 startDragImmediately = startImmediatelyState,
                 >
@@ -212,7 +220,8 @@
     orientation: State<Orientation>,
     enabled: State<Boolean>,
     reverseDirection: State<Boolean>,
-    interactionState: State<InteractionState?>,
+    interactionSource: State<MutableInteractionSource?>,
+    dragStartInteraction: MutableState<DragInteraction.Start?>,
     startDragImmediately: State<Boolean>,
     onDragStarted: State<suspend CoroutineScope.(startedPosition: Offset) -> Unit>,
     onDragStopped: State<suspend CoroutineScope.(velocity: Float) -> Unit>,
@@ -284,7 +293,16 @@
                         overSlopOffset * sign(drag.position.run { if (isVertical()) y else x })
                     if (enabledWhenInteractionAdded) {
                         onDragStarted.value.invoke(this@coroutineScope, adjustedStart)
-                        interactionState.value?.addInteraction(Interaction.Dragged)
+                        launch {
+                            dragStartInteraction.value?.let { oldInteraction ->
+                                interactionSource.value?.emit(
+                                    DragInteraction.Cancel(oldInteraction)
+                                )
+                            }
+                            val interaction = DragInteraction.Start()
+                            interactionSource.value?.emit(interaction)
+                            dragStartInteraction.value = interaction
+                        }
                     }
                     dragState.value.drag(dragPriority = MutatePriority.UserInput) {
                         isDragSuccessful = performDrag(initialDelta, drag, velocityTracker)
@@ -293,7 +311,14 @@
                     isDragSuccessful = false
                 } finally {
                     if (enabledWhenInteractionAdded) {
-                        interactionState.value?.removeInteraction(Interaction.Dragged)
+                        launch {
+                            dragStartInteraction.value?.let { interaction ->
+                                interactionSource.value?.emit(
+                                    DragInteraction.Stop(interaction)
+                                )
+                                dragStartInteraction.value = null
+                            }
+                        }
                     }
                     val velocity =
                         if (isDragSuccessful) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index bc7ebd8..e5936bc 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -20,13 +20,14 @@
 import androidx.compose.animation.core.DecayAnimationSpec
 import androidx.compose.animation.core.animateDecay
 import androidx.compose.animation.defaultDecayAnimationSpec
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.MutatePriority
 import androidx.compose.foundation.gestures.Orientation.Horizontal
 import androidx.compose.foundation.gestures.Orientation.Vertical
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.State
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -47,6 +48,7 @@
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.unit.Velocity
 import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 import kotlin.math.abs
 
@@ -70,8 +72,8 @@
  * behave like bottom to top and left to right will behave like right to left.
  * @param flingBehavior logic describing fling behavior when drag has finished with velocity. If
  * `null`, default from [ScrollableDefaults.flingBehavior] will be used.
- * @param interactionState [InteractionState] that will be updated when this draggable is
- * being dragged, using [Interaction.Dragged].
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * drag events when this scrollable is being dragged.
  */
 fun Modifier.scrollable(
     state: ScrollableState,
@@ -79,7 +81,7 @@
     enabled: Boolean = true,
     reverseDirection: Boolean = false,
     flingBehavior: FlingBehavior? = null,
-    interactionState: InteractionState? = null
+    interactionSource: MutableInteractionSource? = null
 ): Modifier = composed(
     inspectorInfo = debugInspectorInfo {
         name = "scrollable"
@@ -88,12 +90,12 @@
         properties["enabled"] = enabled
         properties["reverseDirection"] = reverseDirection
         properties["flingBehavior"] = flingBehavior
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
     },
     factory = {
         fun Float.reverseIfNeeded(): Float = if (reverseDirection) this * -1 else this
         touchScrollImplementation(
-            interactionState,
+            interactionSource,
             orientation,
             reverseDirection,
             state,
@@ -134,16 +136,20 @@
 @Suppress("ComposableModifierFactory")
 @Composable
 private fun Modifier.touchScrollImplementation(
-    interactionState: InteractionState?,
+    interactionSource: MutableInteractionSource?,
     orientation: Orientation,
     reverseDirection: Boolean,
     controller: ScrollableState,
     flingBehavior: FlingBehavior?,
     enabled: Boolean
 ): Modifier {
-    DisposableEffect(interactionState) {
+    val draggedInteraction = remember { mutableStateOf<DragInteraction.Start?>(null) }
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState?.removeInteraction(Interaction.Dragged)
+            draggedInteraction.value?.let { interaction ->
+                interactionSource?.tryEmit(DragInteraction.Cancel(interaction))
+                draggedInteraction.value = null
+            }
         }
     }
 
@@ -161,13 +167,14 @@
     val orientationState = rememberUpdatedState(orientation)
     val enabledState = rememberUpdatedState(enabled)
     val controllerState = rememberUpdatedState(controller)
-    val interactionStateState = rememberUpdatedState(interactionState)
+    val interactionSourceState = rememberUpdatedState(interactionSource)
     return dragForEachGesture(
         orientation = orientationState,
         enabled = enabledState,
         scrollableState = controllerState,
         nestedScrollDispatcher = nestedScrollDispatcher,
-        interactionState = interactionStateState,
+        interactionSource = interactionSourceState,
+        dragStartInteraction = draggedInteraction,
         scrollLogic = scrollLogic
     ).nestedScroll(nestedScrollConnection, nestedScrollDispatcher.value)
 }
@@ -179,7 +186,8 @@
     enabled: State<Boolean>,
     scrollableState: State<ScrollableState>,
     nestedScrollDispatcher: State<NestedScrollDispatcher>,
-    interactionState: State<InteractionState?>,
+    interactionSource: State<MutableInteractionSource?>,
+    dragStartInteraction: MutableState<DragInteraction.Start?>,
     scrollLogic: State<ScrollingLogic>
 ): Modifier {
     fun isVertical() = orientation.value == Vertical
@@ -265,11 +273,31 @@
                     // remember enabled state when we add interaction to remove later if needed
                     val enabledWhenInteractionAdded = enabled.value
                     if (enabledWhenInteractionAdded) {
-                        interactionState.value?.addInteraction(Interaction.Dragged)
+                        coroutineScope {
+                            launch {
+                                dragStartInteraction.value?.let { oldInteraction ->
+                                    interactionSource.value?.emit(
+                                        DragInteraction.Cancel(oldInteraction)
+                                    )
+                                }
+                                val interaction = DragInteraction.Start()
+                                interactionSource.value?.emit(interaction)
+                                dragStartInteraction.value = interaction
+                            }
+                        }
                     }
                     val isDragSuccessful = mainDragCycle(startEvent, initialDelta, velocityTracker)
                     if (enabledWhenInteractionAdded) {
-                        interactionState.value?.removeInteraction(Interaction.Dragged)
+                        coroutineScope {
+                            launch {
+                                dragStartInteraction.value?.let { interaction ->
+                                    interactionSource.value?.emit(
+                                        DragInteraction.Stop(interaction)
+                                    )
+                                    dragStartInteraction.value = null
+                                }
+                            }
+                        }
                     }
                     if (isDragSuccessful) {
                         nestedScrollDispatcher.value.coroutineScope.launch {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/DragInteraction.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/DragInteraction.kt
new file mode 100644
index 0000000..6f93c2a
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/DragInteraction.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.interaction
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import kotlinx.coroutines.flow.collect
+
+// An interface, not a sealed class, to allow adding new types here in a safe way (and not break
+// exhaustive when clauses)
+/**
+ * An interaction related to drag events.
+ *
+ * @see androidx.compose.foundation.gestures.draggable
+ * @see Start
+ * @see Stop
+ * @see Cancel
+ */
+interface DragInteraction : Interaction {
+    /**
+     * An interaction representing a drag event on a component.
+     *
+     * @see androidx.compose.foundation.gestures.draggable
+     * @see Stop
+     * @see Cancel
+     */
+    class Start : DragInteraction
+
+    /**
+     * An interaction representing the stopping of a [Start] event on a component.
+     *
+     * @property start the source [Start] interaction that is being stopped
+     *
+     * @see androidx.compose.foundation.gestures.draggable
+     * @see Start
+     */
+    class Stop(val start: Start) : DragInteraction
+
+    /**
+     * An interaction representing the cancellation of a [Start] event on a component.
+     *
+     * @property start the source [Start] interaction that is being cancelled
+     *
+     * @see androidx.compose.foundation.gestures.draggable
+     * @see Start
+     */
+    class Cancel(val start: Start) : DragInteraction
+}
+
+/**
+ * Subscribes to this [MutableInteractionSource] and returns a [State] representing whether this
+ * component is dragged or not.
+ *
+ * [DragInteraction] is typically set by interactions
+ * such as [androidx.compose.foundation.gestures.draggable] and
+ * [androidx.compose.foundation.gestures.scrollable], and higher level components such as
+ * [androidx.compose.foundation.lazy.LazyRow], available through
+ * [androidx.compose.foundation.lazy.LazyListState.interactionSource].
+ *
+ * @return [State] representing whether this component is being dragged or not
+ */
+@Composable
+fun InteractionSource.collectIsDraggedAsState(): State<Boolean> {
+    val dragInteractions = remember { mutableStateListOf<DragInteraction.Start>() }
+    LaunchedEffect(this) {
+        interactions.collect { interaction ->
+            when (interaction) {
+                is DragInteraction.Start -> dragInteractions.add(interaction)
+                is DragInteraction.Stop -> dragInteractions.remove(interaction.start)
+                is DragInteraction.Cancel -> dragInteractions.remove(interaction.start)
+            }
+        }
+    }
+    return derivedStateOf { dragInteractions.isNotEmpty() }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/FocusInteraction.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/FocusInteraction.kt
new file mode 100644
index 0000000..3689050
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/FocusInteraction.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.interaction
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import kotlinx.coroutines.flow.collect
+
+// An interface, not a sealed class, to allow adding new types here in a safe way (and not break
+// exhaustive when clauses)
+/**
+ * An interaction related to focus events.
+ *
+ * @see androidx.compose.foundation.focusable
+ * @see Focus
+ * @see Unfocus
+ */
+interface FocusInteraction : Interaction {
+    /**
+     * An interaction representing a focus event on a component.
+     *
+     * @see androidx.compose.foundation.focusable
+     * @see Unfocus
+     */
+    class Focus : FocusInteraction
+
+    /**
+     * An interaction representing a [Focus] event being released on a component.
+     *
+     * @property focus the source [Focus] interaction that is being released
+     *
+     * @see androidx.compose.foundation.focusable
+     * @see Focus
+     */
+    class Unfocus(val focus: Focus) : FocusInteraction
+}
+
+/**
+ * Subscribes to this [MutableInteractionSource] and returns a [State] representing whether this
+ * component is focused or not.
+ *
+ * [FocusInteraction] is typically set by [androidx.compose.foundation.focusable] and focusable
+ * components, such as [androidx.compose.foundation.text.BasicTextField].
+ *
+ * @return [State] representing whether this component is being focused or not
+ */
+@Composable
+fun InteractionSource.collectIsFocusedAsState(): State<Boolean> {
+    val focusInteractions = remember { mutableStateListOf<FocusInteraction.Focus>() }
+    LaunchedEffect(this) {
+        interactions.collect { interaction ->
+            when (interaction) {
+                is FocusInteraction.Focus -> focusInteractions.add(interaction)
+                is FocusInteraction.Unfocus -> focusInteractions.remove(interaction.focus)
+            }
+        }
+    }
+    return derivedStateOf { focusInteractions.isNotEmpty() }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/Interaction.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/Interaction.kt
new file mode 100644
index 0000000..5b7a78d
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/Interaction.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.compose.foundation.interaction
+
+/**
+ * An Interaction represents transient UI state for a component, typically separate from the
+ * actual 'business' state that a component may control. For example, a button typically fires an
+ * `onClick` callback when the button is pressed and released, but it may still want to show
+ * that it is being pressed before this callback is fired. This transient state is represented by
+ * an Interaction, in this case [PressInteraction.Press]. Using Interactions allows you to build
+ * components that respond to these transient, component-owned state changes.
+ *
+ * To emit / observe current Interactions, see [MutableInteractionSource], which represents a
+ * stream of Interactions present for a given component.
+ *
+ * @see InteractionSource
+ * @see MutableInteractionSource
+ */
+interface Interaction
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/InteractionSource.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/InteractionSource.kt
new file mode 100644
index 0000000..4b6c65b
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/InteractionSource.kt
@@ -0,0 +1,144 @@
+/*
+ * 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.compose.foundation.interaction
+
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+
+/**
+ * InteractionSource represents a stream of [Interaction]s corresponding to events emitted by a
+ * component. These [Interaction]s can be used to change how components appear in different
+ * states, such as when a component is pressed or dragged.
+ *
+ * A common use case is [androidx.compose.foundation.indication], where
+ * [androidx.compose.foundation.Indication] implementations can subscribe to an [InteractionSource]
+ * to draw indication for different [Interaction]s, such as a ripple effect for
+ * [PressInteraction.Press] and a state overlay for [DragInteraction.Start].
+ *
+ * For simple cases where you are interested in the binary state of an [Interaction], such as
+ * whether a component is pressed or not, you can use [InteractionSource.collectIsPressedAsState] and other
+ * extension functions that subscribe and return a [Boolean] [State] representing whether the
+ * component is in this state or not.
+ *
+ * @sample androidx.compose.foundation.samples.SimpleInteractionSourceSample
+ *
+ * For more complex cases, such as when building an [androidx.compose.foundation.Indication], the
+ * order of the events can change how a component / indication should be drawn. For example, if a
+ * component is being dragged and then becomes focused, the most recent [Interaction] is
+ * [FocusInteraction.Focus], so the component should appear in a focused state to signal this
+ * event to the user.
+ *
+ * InteractionSource exposes [interactions] to support these use cases - a
+ * [Flow] representing the stream of all emitted [Interaction]s. This also provides more
+ * information, such as the press position of [PressInteraction.Press], so you can show an effect
+ * at the specific point the component was pressed, and whether the press was
+ * [PressInteraction.Release] or [PressInteraction.Cancel], for cases when a component
+ * should behave differently if the press was released normally or interrupted by another gesture.
+ *
+ * You can collect from [interactions] as you would with any other [Flow]:
+ *
+ * @sample androidx.compose.foundation.samples.InteractionSourceFlowSample
+ *
+ * To emit [Interaction]s so that consumers can react to them, see [MutableInteractionSource].
+ *
+ * @see MutableInteractionSource
+ * @see Interaction
+ */
+@Stable
+interface InteractionSource {
+    /**
+     * [Flow] representing the stream of all [Interaction]s emitted through this
+     * [InteractionSource]. This can be used to see [Interaction]s emitted in order, and with
+     * additional metadata, such as the press position for [PressInteraction.Press].
+     *
+     * @sample androidx.compose.foundation.samples.InteractionSourceFlowSample
+     */
+    val interactions: Flow<Interaction>
+}
+
+/**
+ * MutableInteractionSource represents a stream of [Interaction]s corresponding to events emitted
+ * by a component. These [Interaction]s can be used to change how components appear
+ * in different states, such as when a component is pressed or dragged.
+ *
+ * Lower level interaction APIs such as [androidx.compose.foundation.clickable] and
+ * [androidx.compose.foundation.gestures.draggable] have an [MutableInteractionSource] parameter,
+ * which allows you to hoist an [MutableInteractionSource] and combine multiple interactions into
+ * one event stream.
+ *
+ * MutableInteractionSource exposes [emit] and [tryEmit] functions. These emit the provided
+ * [Interaction] to the underlying [interactions] [Flow], allowing consumers to react to these
+ * new [Interaction]s.
+ *
+ * An instance of MutableInteractionSource can be created by using the
+ * [MutableInteractionSource] factory function. This instance should be [remember]ed before it is
+ * passed to other components that consume it.
+ *
+ * @see InteractionSource
+ * @see Interaction
+ */
+@Stable
+interface MutableInteractionSource : InteractionSource {
+    /**
+     * Emits [interaction] into [interactions].
+     * This method is not thread-safe and should not be invoked concurrently.
+     *
+     * @see tryEmit
+     */
+    suspend fun emit(interaction: Interaction)
+
+    /**
+     * Tries to emit [interaction] into [interactions] without suspending. It returns `true` if the
+     * value was emitted successfully.
+     *
+     * @see emit
+     */
+    fun tryEmit(interaction: Interaction): Boolean
+}
+
+/**
+ * Return a new [MutableInteractionSource] that can be hoisted and provided to components,
+ * allowing listening to [Interaction] changes inside those components.
+ *
+ * This should be [remember]ed before it is provided to components, so it can maintain its state
+ * across compositions.
+ *
+ * @see InteractionSource
+ * @see MutableInteractionSource
+ */
+fun MutableInteractionSource(): MutableInteractionSource = MutableInteractionSourceImpl()
+
+@Stable
+private class MutableInteractionSourceImpl : MutableInteractionSource {
+    // TODO: consider replay for new indication instances during events?
+    override val interactions = MutableSharedFlow<Interaction>(
+        extraBufferCapacity = 16,
+        >
+    )
+
+    override suspend fun emit(interaction: Interaction) {
+        interactions.emit(interaction)
+    }
+
+    override fun tryEmit(interaction: Interaction): Boolean {
+        return interactions.tryEmit(interaction)
+    }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/PressInteraction.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/PressInteraction.kt
new file mode 100644
index 0000000..71720b8b
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/interaction/PressInteraction.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.interaction
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.geometry.Offset
+import kotlinx.coroutines.flow.collect
+
+// An interface, not a sealed class, to allow adding new types here in a safe way (and not break
+// exhaustive when clauses)
+/**
+ * An interaction related to press events.
+ *
+ * @see androidx.compose.foundation.clickable
+ * @see Press
+ * @see Release
+ * @see Cancel
+ */
+interface PressInteraction : Interaction {
+    /**
+     * An interaction representing a press event on a component.
+     *
+     * @property pressPosition the [Offset] describing where this press event occurred within the
+     * component
+     *
+     * @see androidx.compose.foundation.clickable
+     * @see Release
+     * @see Cancel
+     */
+    class Press(val pressPosition: Offset) : PressInteraction
+
+    /**
+     * An interaction representing the release of a [Press] event on a component.
+     *
+     * @property press the source [Press] interaction that is being released
+     *
+     * @see androidx.compose.foundation.clickable
+     * @see Press
+     */
+    class Release(val press: Press) : PressInteraction
+
+    /**
+     * An interaction representing the cancellation of a [Press] event on a component.
+     *
+     * @property press the source [Press] interaction that is being cancelled
+     *
+     * @see androidx.compose.foundation.clickable
+     * @see Press
+     */
+    class Cancel(val press: Press) : PressInteraction
+}
+
+/**
+ * Subscribes to this [MutableInteractionSource] and returns a [State] representing whether this
+ * component is pressed or not.
+ *
+ * [PressInteraction] is typically set by [androidx.compose.foundation.clickable] and clickable
+ * higher level components, such as buttons.
+ *
+ * @return [State] representing whether this component is being pressed or not
+ */
+@Composable
+fun InteractionSource.collectIsPressedAsState(): State<Boolean> {
+    val pressInteractions = remember { mutableStateListOf<PressInteraction.Press>() }
+    LaunchedEffect(this) {
+        interactions.collect { interaction ->
+            when (interaction) {
+                is PressInteraction.Press -> pressInteractions.add(interaction)
+                is PressInteraction.Release -> pressInteractions.remove(interaction.press)
+                is PressInteraction.Cancel -> pressInteractions.remove(interaction.press)
+            }
+        }
+    }
+    return derivedStateOf { pressInteractions.isNotEmpty() }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
index 32f0936..0bd9b0a 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
@@ -83,7 +83,7 @@
             .scrollable(
                 orientation = if (isVertical) Orientation.Vertical else Orientation.Horizontal,
                 reverseDirection = reverseScrollDirection,
-                interactionState = state.interactionState,
+                interactionSource = state.internalInteractionSource,
                 flingBehavior = flingBehavior,
                 state = state
             )
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
index 1fc23caf..d539941 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListState.kt
@@ -17,8 +17,8 @@
 package androidx.compose.foundation.lazy
 
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.MutatePriority
 import androidx.compose.foundation.gestures.ScrollScope
 import androidx.compose.foundation.gestures.ScrollableState
@@ -96,11 +96,13 @@
     val layoutInfo: LazyListLayoutInfo get() = layoutInfoState.value
 
     /**
-     * interactionState [InteractionState] that will be updated when component with this
-     * state is being scrolled by dragging, using [Interaction.Dragged]. If you want to know whether
-     * the fling (or animated scroll) is in progress, use [isScrollInProgress].
+     * [InteractionSource] that will be used to dispatch drag events when this
+     * list is being dragged. If you want to know whether the fling (or animated scroll) is in
+     * progress, use [isScrollInProgress].
      */
-    val interactionState: InteractionState = InteractionState()
+    val interactionSource: InteractionSource get() = internalInteractionSource
+
+    internal val internalInteractionSource: MutableInteractionSource = MutableInteractionSource()
 
     /**
      * The amount of scroll to be consumed in the next layout pass.  Scrolling forward is negative
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
index e9f30bb..582ea60 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Selectable.kt
@@ -17,8 +17,7 @@
 package androidx.compose.foundation.selection
 
 import androidx.compose.foundation.Indication
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.LocalIndication
 import androidx.compose.foundation.Strings
 import androidx.compose.foundation.clickable
@@ -41,9 +40,9 @@
  * If you want to make an item support on/off capabilities without being part of a set, consider
  * using [Modifier.toggleable]
  *
- * This version has no [InteractionState] or [Indication] parameters, default indication from
- * [LocalIndication] will be used. To specify [InteractionState] or [Indication], use another
- * overload.
+ * This version has no [MutableInteractionSource] or [Indication] parameters, default
+ * indication from [LocalIndication] will be used. To specify [MutableInteractionSource] or
+ * [Indication], use another overload.
  *
  * @sample androidx.compose.foundation.samples.SelectableSample
  *
@@ -72,7 +71,7 @@
         selected = selected,
         enabled = enabled,
         role = role,
-        interactionState = remember { InteractionState() },
+        interactionSource = remember { MutableInteractionSource() },
         indication = LocalIndication.current,
         >
     )
@@ -88,14 +87,14 @@
  * If you want to make an item support on/off capabilities without being part of a set, consider
  * using [Modifier.toggleable]
  *
- * This version requires both [InteractionState] and [Indication] to work properly. Use another
+ * This version requires both [MutableInteractionSource] and [Indication] to work properly. Use another
  * overload if you don't need these parameters.
  *
  * @sample androidx.compose.foundation.samples.SelectableSample
  *
  * @param selected whether or not this item is selected in a mutually exclusion set
- * @param interactionState [InteractionState] that will be updated when this element is
- * pressed, using [Interaction.Pressed]
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * press events when this selectable is being pressed.
  * @param indication indication to be shown when the modified element is pressed. By default,
  * the indication from [LocalIndication] will be used. Set to `null` to show no indication, or
  * current value from [LocalIndication] to show theme default
@@ -107,7 +106,7 @@
  */
 fun Modifier.selectable(
     selected: Boolean,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     role: Role? = null,
@@ -117,7 +116,7 @@
         Modifier.clickable(
             enabled = enabled,
             role = role,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             indication = indication,
             >
         ).semantics {
@@ -130,7 +129,7 @@
         properties["selected"] = selected
         properties["enabled"] = enabled
         properties["role"] = role
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["indication"] = indication
         properties["onClick"] = onClick
     }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
index bc09caf..9e500518 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/selection/Toggleable.kt
@@ -17,13 +17,15 @@
 package androidx.compose.foundation.selection
 
 import androidx.compose.foundation.Indication
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.Strings
 import androidx.compose.foundation.indication
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.foundation.legacygestures.pressIndicatorGestureFilter
@@ -40,12 +42,13 @@
 import androidx.compose.ui.state.ToggleableState.Indeterminate
 import androidx.compose.ui.state.ToggleableState.Off
 import androidx.compose.ui.state.ToggleableState.On
+import kotlinx.coroutines.launch
 
 /**
  * Configure component to make it toggleable via input and accessibility events
  *
- * This version has no [InteractionState] or [Indication] parameters, default indication from
- * [LocalIndication] will be used. To specify [InteractionState] or [Indication], use another
+ * This version has no [MutableInteractionSource] or [Indication] parameters, default indication from
+ * [LocalIndication] will be used. To specify [MutableInteractionSource] or [Indication], use another
  * overload.
  *
  * @sample androidx.compose.foundation.samples.ToggleableSample
@@ -79,7 +82,7 @@
          onValueChange(!value) },
         enabled = enabled,
         role = role,
-        interactionState = remember { InteractionState() },
+        interactionSource = remember { MutableInteractionSource() },
         indication = LocalIndication.current
     )
 }
@@ -87,7 +90,7 @@
 /**
  * Configure component to make it toggleable via input and accessibility events.
  *
- * This version requires both [InteractionState] and [Indication] to work properly. Use another
+ * This version requires both [MutableInteractionSource] and [Indication] to work properly. Use another
  * overload if you don't need these parameters.
  *
  * @sample androidx.compose.foundation.samples.ToggleableSample
@@ -95,8 +98,8 @@
  * @see [Modifier.triStateToggleable] if you require support for an indeterminate state.
  *
  * @param value whether Toggleable is on or off
- * @param interactionState [InteractionState] that will be updated when this toggleable is
- * pressed, using [Interaction.Pressed]
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [PressInteraction.Press] when this toggleable is being pressed.
  * @param indication indication to be shown when modified element is pressed. Be default,
  * indication from [LocalIndication] will be used. Pass `null` to show no indication, or
  * current value from [LocalIndication] to show theme default
@@ -109,7 +112,7 @@
  */
 fun Modifier.toggleable(
     value: Boolean,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     role: Role? = null,
@@ -120,7 +123,7 @@
         properties["value"] = value
         properties["enabled"] = enabled
         properties["role"] = role
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["indication"] = indication
         properties["onValueChange"] = onValueChange
     },
@@ -130,7 +133,7 @@
              onValueChange(!value) },
             enabled = enabled,
             role = role,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             indication = indication
         )
     }
@@ -143,9 +146,9 @@
  * TriStateToggleable should be used when there are dependent Toggleables associated to this
  * component and those can have different values.
  *
- * This version has no [InteractionState] or [Indication] parameters, default indication from
- * [LocalIndication] will be used. To specify [InteractionState] or [Indication], use another
- * overload.
+ * This version has no [MutableInteractionSource] or [Indication] parameters, default indication
+ * from [LocalIndication] will be used. To specify [MutableInteractionSource] or [Indication],
+ * use another overload.
  *
  * @sample androidx.compose.foundation.samples.TriStateToggleableSample
  *
@@ -176,7 +179,7 @@
         state,
         enabled,
         role,
-        remember { InteractionState() },
+        remember { MutableInteractionSource() },
         LocalIndication.current,
         onClick
     )
@@ -189,7 +192,7 @@
  * TriStateToggleable should be used when there are dependent Toggleables associated to this
  * component and those can have different values.
  *
- * This version requires both [InteractionState] and [Indication] to work properly. Use another
+ * This version requires both [MutableInteractionSource] and [Indication] to work properly. Use another
  * overload if you don't need these parameters.
  *
  * @sample androidx.compose.foundation.samples.TriStateToggleableSample
@@ -197,8 +200,8 @@
  * @see [Modifier.toggleable] if you want to support only two states: on and off
  *
  * @param state current value for the component
- * @param interactionState [InteractionState] that will be updated when this toggleable is
- * pressed, using [Interaction.Pressed]
+ * @param interactionSource [MutableInteractionSource] that will be used to emit
+ * [PressInteraction.Press] when this triStateToggleable is being pressed.
  * @param indication indication to be shown when modified element is pressed. Be default,
  * indication from [LocalIndication] will be used. Pass `null` to show no indication, or
  * current value from [LocalIndication] to show theme default
@@ -210,7 +213,7 @@
  */
 fun Modifier.triStateToggleable(
     state: ToggleableState,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     enabled: Boolean = true,
     role: Role? = null,
@@ -221,12 +224,12 @@
         properties["state"] = state
         properties["enabled"] = enabled
         properties["role"] = role
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["indication"] = indication
         properties["onClick"] = onClick
     },
     factory = {
-        toggleableImpl(state, enabled, role, interactionState, indication, onClick)
+        toggleableImpl(state, enabled, role, interactionSource, indication, onClick)
     }
 )
 
@@ -235,10 +238,12 @@
     state: ToggleableState,
     enabled: Boolean,
     role: Role? = null,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     indication: Indication?,
     onClick: () -> Unit
 ): Modifier = composed {
+    val scope = rememberCoroutineScope()
+    val pressedInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
     // TODO(pavlis): Handle multiple states for Semantics
     val semantics = Modifier.semantics(mergeDescendants = true) {
         if (role != null) {
@@ -259,23 +264,55 @@
     val interactionUpdate =
         if (enabled) {
             Modifier.pressIndicatorGestureFilter(
-                 interactionState.addInteraction(Interaction.Pressed, it) },
-                 interactionState.removeInteraction(Interaction.Pressed) },
-                 interactionState.removeInteraction(Interaction.Pressed) }
+                >
+                    scope.launch {
+                        // Remove any old interactions if we didn't fire stop / cancel properly
+                        pressedInteraction.value?.let { oldValue ->
+                            val interaction = PressInteraction.Cancel(oldValue)
+                            interactionSource.emit(interaction)
+                            pressedInteraction.value = null
+                        }
+                        val interaction = PressInteraction.Press(it)
+                        interactionSource.emit(interaction)
+                        pressedInteraction.value = interaction
+                    }
+                },
+                >
+                    scope.launch {
+                        pressedInteraction.value?.let {
+                            val interaction = PressInteraction.Release(it)
+                            interactionSource.emit(interaction)
+                            pressedInteraction.value = null
+                        }
+                    }
+                },
+                >
+                    scope.launch {
+                        pressedInteraction.value?.let {
+                            val interaction = PressInteraction.Cancel(it)
+                            interactionSource.emit(interaction)
+                            pressedInteraction.value = null
+                        }
+                    }
+                }
             )
         } else {
             Modifier
         }
     val click = if (enabled) Modifier.tapGestureFilter { onClick() } else Modifier
 
-    DisposableEffect(interactionState) {
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState.removeInteraction(Interaction.Pressed)
+            pressedInteraction.value?.let { oldValue ->
+                val interaction = PressInteraction.Cancel(oldValue)
+                interactionSource.tryEmit(interaction)
+                pressedInteraction.value = null
+            }
         }
     }
     this
         .then(semantics)
-        .indication(interactionState, indication)
+        .indication(interactionSource, indication)
         .then(interactionUpdate)
         .then(click)
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
index 0751e09..e17f717 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
@@ -16,8 +16,8 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -101,10 +101,10 @@
  * communicating with platform text input service, e.g. software keyboard on Android. Called with
  * [SoftwareKeyboardController] instance which can be used for requesting input show/hide software
  * keyboard.
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this TextField. You can create and pass in your own remembered [InteractionState]
- * if you want to read the [InteractionState] and customize the appearance / behavior of this
- * TextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this TextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this TextField in different [Interaction]s.
  * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
  * provided, there will be no cursor drawn
  * @param decorationBox Composable lambda that allows to add decorations around text field, such
@@ -129,7 +129,7 @@
     visualTransformation: VisualTransformation = VisualTransformation.None,
     onTextLayout: (TextLayoutResult) -> Unit = {},
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     cursorBrush: Brush = SolidColor(Color.Black),
     decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
         @Composable { innerTextField -> innerTextField() }
@@ -156,7 +156,7 @@
         >
         >
         cursorBrush = cursorBrush,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         singleLine = singleLine,
         decorationBox = decorationBox
     )
@@ -227,10 +227,10 @@
  * communicating with platform text input service, e.g. software keyboard on Android. Called with
  * [SoftwareKeyboardController] instance which can be used for requesting input show/hide software
  * keyboard.
- * @param interactionState The [InteractionState] representing the different [Interaction]s
- * present on this TextField. You can create and pass in your own remembered [InteractionState]
- * if you want to read the [InteractionState] and customize the appearance / behavior of this
- * TextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this TextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this TextField in different [Interaction]s.
  * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
  * provided, there will be no cursor drawn
  * @param decorationBox Composable lambda that allows to add decorations around text field, such
@@ -255,7 +255,7 @@
     visualTransformation: VisualTransformation = VisualTransformation.None,
     onTextLayout: (TextLayoutResult) -> Unit = {},
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     cursorBrush: Brush = SolidColor(Color.Black),
     decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
         @Composable { innerTextField -> innerTextField() }
@@ -267,7 +267,7 @@
         textStyle = textStyle,
         visualTransformation = visualTransformation,
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         >
         cursorBrush = cursorBrush,
         imeOptions = keyboardOptions.toImeOptions(singleLine = singleLine),
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index c1660be..f4b7b91 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -17,9 +17,9 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.text.selection.LocalTextSelectionColors
 import androidx.compose.foundation.text.selection.SimpleLayout
@@ -118,9 +118,6 @@
  * @param onValueChange Called when the input service updates the values in [TextFieldValue].
  * @param modifier optional [Modifier] for this text field.
  * @param textStyle Style configuration that applies at character level such as color, font etc.
- * @param onImeActionPerformed Called when the input service requested an IME action. When the
- * input service emitted an IME action, this callback is called with the emitted IME action. Note
- * that this IME action may be different from what you specified in [imeAction].
  * @param visualTransformation The visual transformation filter for changing the visual
  * representation of the input. By default no visual transformation is applied.
  * @param onTextLayout Callback that is executed when a new text layout is calculated.
@@ -128,10 +125,10 @@
  * communicating with platform text input service, e.g. software keyboard on Android. Called with
  * [SoftwareKeyboardController] instance which can be used for requesting input show/hide software
  * keyboard.
- * @param interactionState The [InteractionState] representing the different [Interaction]s
- * present on this TextField. You can create and pass in your own remembered [InteractionState]
- * if you want to read the [InteractionState] and customize the appearance / behavior of this
- * TextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this CoreTextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this CoreTextField in different [Interaction]s.
  * @param cursorBrush [Brush] to paint cursor with. If [SolidColor] with [Color.Unspecified]
  * provided, there will be no cursor drawn
  * @param softWrap Whether the text should break at soft line breaks. If false, the glyphs in the
@@ -164,7 +161,7 @@
     visualTransformation: VisualTransformation = VisualTransformation.None,
     onTextLayout: (TextLayoutResult) -> Unit = {},
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState? = null,
+    interactionSource: MutableInteractionSource? = null,
     cursorBrush: Brush = SolidColor(Color.Unspecified),
     softWrap: Boolean = true,
     maxLines: Int = Int.MAX_VALUE,
@@ -257,7 +254,7 @@
     val focusModifier = Modifier.textFieldFocusModifier(
         enabled = enabled,
         focusRequester = focusRequester,
-        interactionState = interactionState
+        interactionSource = interactionSource
     ) {
         if (state.hasFocus == it.isFocused) {
             return@textFieldFocusModifier
@@ -305,7 +302,7 @@
         Modifier.longPressDragGestureFilter(manager.touchSelectionObserver, enabled)
 
     val pointerModifier = if (isInTouchMode) {
-        Modifier.pressGestureFilter(interactionState = interactionState, enabled = enabled)
+        Modifier.pressGestureFilter(interactionSource = interactionSource, enabled = enabled)
             .then(selectionModifier)
             .then(focusRequestTapModifier)
     } else {
@@ -445,7 +442,7 @@
     // Modifiers that should be applied to the outer text field container. Usually those include
     // gesture and semantics modifiers.
     val decorationBoxModifier = modifier
-        .textFieldScrollable(scrollerPosition, interactionState, enabled)
+        .textFieldScrollable(scrollerPosition, interactionSource, enabled)
         .then(pointerModifier)
         .then(semanticsModifier)
         .then(focusModifier)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
index 7087aaf..af50a91 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
@@ -18,7 +18,7 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.focusable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
@@ -45,12 +45,12 @@
 internal fun Modifier.textFieldFocusModifier(
     enabled: Boolean,
     focusRequester: FocusRequester,
-    interactionState: InteractionState?,
+    interactionSource: MutableInteractionSource?,
     onFocusChanged: (FocusState) -> Unit
 ) = this
     .focusRequester(focusRequester)
     .onFocusChanged(onFocusChanged)
-    .focusable(interactionState = interactionState, enabled = enabled)
+    .focusable(interactionSource = interactionSource, enabled = enabled)
 
 // Mouse
 internal fun Modifier.mouseDragGestureFilter(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt
index 9225346..493e81c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldPressGestureFilter.kt
@@ -16,35 +16,67 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
+import kotlinx.coroutines.launch
 import androidx.compose.foundation.legacygestures.pressIndicatorGestureFilter
 
 /**
- * Required for the press [InteractionState] consistency for TextField.
+ * Required for the press [MutableInteractionSource] consistency for TextField.
  */
 @Suppress("ModifierInspectorInfo", "DEPRECATION")
 internal fun Modifier.pressGestureFilter(
-    interactionState: InteractionState?,
+    interactionSource: MutableInteractionSource?,
     enabled: Boolean = true
 ): Modifier = if (enabled) composed {
-    DisposableEffect(interactionState) {
+    val scope = rememberCoroutineScope()
+    val pressedInteraction = remember { mutableStateOf<PressInteraction.Press?>(null) }
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState?.removeInteraction(Interaction.Pressed)
+            pressedInteraction.value?.let { oldValue ->
+                val interaction = PressInteraction.Cancel(oldValue)
+                interactionSource?.tryEmit(interaction)
+                pressedInteraction.value = null
+            }
         }
     }
     pressIndicatorGestureFilter(
         >
-            interactionState?.addInteraction(Interaction.Pressed, it)
+            scope.launch {
+                // Remove any old interactions if we didn't fire stop / cancel properly
+                pressedInteraction.value?.let { oldValue ->
+                    val interaction = PressInteraction.Cancel(oldValue)
+                    interactionSource?.emit(interaction)
+                    pressedInteraction.value = null
+                }
+                val interaction = PressInteraction.Press(it)
+                interactionSource?.emit(interaction)
+                pressedInteraction.value = interaction
+            }
         },
         >
-            interactionState?.removeInteraction(Interaction.Pressed)
+            scope.launch {
+                pressedInteraction.value?.let {
+                    val interaction = PressInteraction.Release(it)
+                    interactionSource?.emit(interaction)
+                    pressedInteraction.value = null
+                }
+            }
         },
         >
-            interactionState?.removeInteraction(Interaction.Pressed)
+            scope.launch {
+                pressedInteraction.value?.let {
+                    val interaction = PressInteraction.Cancel(it)
+                    interactionSource?.emit(interaction)
+                    pressedInteraction.value = null
+                }
+            }
         }
     )
 } else this
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
index 9e138c8..fd4438b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldScroll.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.rememberScrollableState
 import androidx.compose.foundation.gestures.scrollable
@@ -51,13 +51,13 @@
 // Scrollable
 internal fun Modifier.textFieldScrollable(
     scrollerPosition: TextFieldScrollerPosition,
-    interactionState: InteractionState? = null,
+    interactionSource: MutableInteractionSource? = null,
     enabled: Boolean = true
 ) = composed(
     inspectorInfo = debugInspectorInfo {
         name = "textFieldScrollable"
         properties["scrollerPosition"] = scrollerPosition
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["enabled"] = enabled
     }
 ) {
@@ -79,7 +79,7 @@
         orientation = scrollerPosition.orientation,
         reverseDirection = reverseDirection,
         state = controller,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         enabled = enabled && scrollerPosition.maximum != 0f
     )
     scroll
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
index 29e9e42..d107f34 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
@@ -16,11 +16,11 @@
 
 package androidx.compose.foundation.text.selection
 
-import androidx.compose.foundation.Interaction
 import androidx.compose.foundation.text.isInTouchMode
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -97,7 +97,8 @@
         // cross-composable selection.
         SimpleLayout(modifier = modifier.then(manager.modifier)) {
             children()
-            if (isInTouchMode && manager.interactionState.contains(Interaction.Focused)) {
+            val isFocused = manager.interactionSource.collectIsFocusedAsState()
+            if (isInTouchMode && isFocused.value) {
                 manager.selection?.let {
                     for (isStartHandle in listOf(true, false)) {
                         SelectionHandle(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
index 1a0565e..d630533 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionManager.kt
@@ -18,7 +18,7 @@
 
 package androidx.compose.foundation.text.selection
 
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.focusable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
@@ -95,9 +95,9 @@
     var focusRequester: FocusRequester = FocusRequester()
 
     /**
-     * InteractionState corresponds to the focusRequester, it will return trun.
+     * MutableInteractionSource for the selection container, containing focus interactions.
      */
-    val interactionState: InteractionState = InteractionState()
+    val interactionSource: MutableInteractionSource = MutableInteractionSource()
 
     /**
      * Modifier for selection container.
@@ -110,7 +110,7 @@
                 onRelease()
             }
         }
-        .focusable(interactionState = interactionState)
+        .focusable(interactionSource = interactionSource)
         .onKeyEvent {
             if (isCopyKeyEvent(it)) {
                 copy()
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt
index 7f10c00..20ecff2 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/Scrollbar.desktop.kt
@@ -29,6 +29,7 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.Modifier
@@ -37,6 +38,8 @@
 import androidx.compose.foundation.legacygestures.DragObserver
 import androidx.compose.foundation.legacygestures.pressIndicatorGestureFilter
 import androidx.compose.foundation.legacygestures.rawDragGestureFilter
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.graphics.Shape
@@ -50,6 +53,7 @@
 import androidx.compose.ui.unit.constrainWidth
 import androidx.compose.ui.unit.dp
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlin.math.roundToInt
 import kotlin.math.sign
@@ -110,20 +114,20 @@
  * @param adapter [ScrollbarAdapter] that will be used to communicate with scrollable component
  * @param modifier the modifier to apply to this layout
  * @param style [ScrollbarStyle] to define visual style of scrollbar
- * @param interactionState [InteractionState] that will be updated when the element with this
- * state is being dragged, using [Interaction.Dragged]
+ * @param interactionSource [MutableInteractionSource] that will be used to dispatch
+ * [DragInteraction.Start] when this Scrollbar is being dragged.
  */
 @Composable
 fun VerticalScrollbar(
     adapter: ScrollbarAdapter,
     modifier: Modifier = Modifier,
     style: ScrollbarStyle = ScrollbarStyleAmbient.current,
-    interactionState: InteractionState = remember { InteractionState() }
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
 ) = Scrollbar(
     adapter,
     modifier,
     style,
-    interactionState,
+    interactionSource,
     isVertical = true
 )
 
@@ -150,36 +154,41 @@
  * @param adapter [ScrollbarAdapter] that will be used to communicate with scrollable component
  * @param modifier the modifier to apply to this layout
  * @param style [ScrollbarStyle] to define visual style of scrollbar
- * @param interactionState [InteractionState] that will be updated when the element with this
- * state is being dragged, using [Interaction.Dragged]
+ * @param interactionSource [MutableInteractionSource] that will be used to dispatch
+ * [DragInteraction.Start] when this Scrollbar is being dragged.
  */
 @Composable
 fun HorizontalScrollbar(
     adapter: ScrollbarAdapter,
     modifier: Modifier = Modifier,
     style: ScrollbarStyle = ScrollbarStyleAmbient.current,
-    interactionState: InteractionState = remember { InteractionState() }
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
 ) = Scrollbar(
     adapter,
     modifier,
     style,
-    interactionState,
+    interactionSource,
     isVertical = false
 )
 
 // TODO(demin): do we need to stop dragging if cursor is beyond constraints?
-// TODO(demin): add Interaction.Hovered to interactionState
+// TODO(demin): add Interaction.Hovered to interactionSource
 @Composable
 private fun Scrollbar(
     adapter: ScrollbarAdapter,
     modifier: Modifier = Modifier,
     style: ScrollbarStyle,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     isVertical: Boolean
 ) = with(LocalDensity.current) {
-    DisposableEffect(interactionState) {
+    val scope = rememberCoroutineScope()
+    val dragInteraction = remember { mutableStateOf<DragInteraction.Start?>(null) }
+    DisposableEffect(interactionSource) {
         onDispose {
-            interactionState.removeInteraction(Interaction.Dragged)
+            dragInteraction.value?.let { interaction ->
+                interactionSource.tryEmit(DragInteraction.Cancel(interaction))
+                dragInteraction.value = null
+            }
         }
     }
 
@@ -204,15 +213,38 @@
 
     val dragObserver = object : DragObserver {
         override fun onStart(downPosition: Offset) {
-            interactionState.addInteraction(Interaction.Dragged)
+            scope.launch {
+                dragInteraction.value?.let { oldInteraction ->
+                    interactionSource.emit(
+                        DragInteraction.Cancel(oldInteraction)
+                    )
+                }
+                val interaction = DragInteraction.Start()
+                interactionSource.emit(interaction)
+                dragInteraction.value = interaction
+            }
         }
 
         override fun onStop(velocity: Offset) {
-            interactionState.removeInteraction(Interaction.Dragged)
+            scope.launch {
+                dragInteraction.value?.let { interaction ->
+                    interactionSource.emit(
+                        DragInteraction.Stop(interaction)
+                    )
+                    dragInteraction.value = null
+                }
+            }
         }
 
         override fun onCancel() {
-            interactionState.removeInteraction(Interaction.Dragged)
+            scope.launch {
+                dragInteraction.value?.let { interaction ->
+                    interactionSource.emit(
+                        DragInteraction.Cancel(interaction)
+                    )
+                    dragInteraction.value = null
+                }
+            }
         }
 
         override fun onDrag(dragDistance: Offset): Offset {
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/InteractionStateTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/InteractionStateTest.kt
deleted file mode 100644
index 0c6969a..0000000
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/InteractionStateTest.kt
+++ /dev/null
@@ -1,60 +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.compose.foundation
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class InteractionStateTest {
-
-    private object TestInteraction1 : Interaction
-    private object TestInteraction2 : Interaction
-    private object TestInteraction3 : Interaction
-
-    @Test
-    fun orderingIsPreserved() {
-        val state = InteractionState()
-
-        state.addInteraction(TestInteraction1)
-        state.addInteraction(TestInteraction2)
-
-        assertThat(state.value)
-            .containsExactlyElementsIn(
-                listOf(TestInteraction1, TestInteraction2)
-            )
-            .inOrder()
-
-        state.addInteraction(TestInteraction3)
-
-        assertThat(state.value)
-            .containsExactlyElementsIn(
-                listOf(TestInteraction1, TestInteraction2, TestInteraction3)
-            )
-            .inOrder()
-
-        state.removeInteraction(TestInteraction2)
-
-        assertThat(state.value)
-            .containsExactlyElementsIn(
-                listOf(TestInteraction1, TestInteraction3)
-            )
-            .inOrder()
-    }
-}
diff --git a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt
index d0c2343..09ad441 100644
--- a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt
+++ b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/Ripple.kt
@@ -20,20 +20,20 @@
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.LinearEasing
 import androidx.compose.animation.core.TweenSpec
+import androidx.compose.foundation.interaction.DragInteraction
 import androidx.compose.foundation.Indication
 import androidx.compose.foundation.IndicationInstance
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.RememberObserver
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
-import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateMapOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.drawscope.ContentDrawScope
 import androidx.compose.ui.graphics.drawscope.DrawScope
@@ -41,8 +41,7 @@
 import androidx.compose.ui.graphics.isSpecified
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.isUnspecified
-import androidx.compose.ui.util.fastForEach
-import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
 /**
@@ -51,7 +50,7 @@
  * A Ripple is a Material implementation of [Indication] that expresses different [Interaction]s
  * by drawing ripple animations and state layers.
  *
- * A Ripple responds to [Interaction.Pressed] by starting a new [RippleAnimation], and
+ * A Ripple responds to [PressInteraction.Press] by starting a new [RippleAnimation], and
  * responds to other [Interaction]s by showing a fixed [StateLayer] with varying alpha values
  * depending on the [Interaction].
  *
@@ -90,7 +89,7 @@
  * A Ripple is a Material implementation of [Indication] that expresses different [Interaction]s
  * by drawing ripple animations and state layers.
  *
- * A Ripple responds to [Interaction.Pressed] by starting a new [RippleAnimation], and
+ * A Ripple responds to [PressInteraction.Press] by starting a new [RippleAnimation], and
  * responds to other [Interaction]s by showing a fixed [StateLayer] with varying alpha values
  * depending on the [Interaction].
  *
@@ -110,7 +109,7 @@
     private val color: State<Color>,
 ) : Indication {
     @Composable
-    override fun rememberUpdatedInstance(interactionState: InteractionState): IndicationInstance {
+    override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance {
         val theme = LocalRippleTheme.current
         val color = rememberUpdatedState(
             if (color.value.isSpecified) {
@@ -119,11 +118,29 @@
                 theme.defaultColor()
             }
         )
-        val rippleAlpha = theme.rippleAlpha()
-        val scope = rememberCoroutineScope()
-        return remember(this, interactionState, rippleAlpha, scope) {
-            RippleIndicationInstance(interactionState, bounded, radius, color, rippleAlpha, scope)
+        val rippleAlpha = rememberUpdatedState(theme.rippleAlpha())
+        val instance = remember(interactionSource, this) {
+            RippleIndicationInstance(bounded, radius, color, rippleAlpha)
         }
+        LaunchedEffect(interactionSource, instance) {
+            interactionSource.interactions.collect { interaction ->
+                when (interaction) {
+                    is PressInteraction.Press -> {
+                        launch {
+                            instance.addRipple(interaction)
+                        }
+                    }
+                    is PressInteraction.Release -> {
+                        instance.removeRipple(interaction.press)
+                    }
+                    is PressInteraction.Cancel -> {
+                        instance.removeRipple(interaction.press)
+                    }
+                    else -> instance.updateStateLayer(interaction)
+                }
+            }
+        }
+        return instance
     }
 
     // to force stability on this indication we need equals and hashcode, there's no value in
@@ -148,68 +165,51 @@
 }
 
 private class RippleIndicationInstance constructor(
-    private val interactionState: InteractionState,
     private val bounded: Boolean,
     private val radius: Dp,
     private val color: State<Color>,
-    private val rippleAlpha: RippleAlpha,
-    private val scope: CoroutineScope
+    private val rippleAlpha: State<RippleAlpha>
 ) : RememberObserver, IndicationInstance {
 
-    private val stateLayer = StateLayer(bounded, rippleAlpha, scope)
+    private val stateLayer = StateLayer(bounded, rippleAlpha)
 
-    private val ripples = mutableStateListOf<RippleAnimation>()
-    private var currentPressPosition: Offset? = null
-    private var currentRipple: RippleAnimation? = null
+    private val ripples = mutableStateMapOf<PressInteraction.Press, RippleAnimation>()
 
     override fun ContentDrawScope.drawIndication() {
         val color = color.value
-        val targetRadius = if (radius.isUnspecified) {
-            getRippleEndRadius(bounded, size)
-        } else {
-            radius.toPx()
-        }
         drawContent()
         with(stateLayer) {
-            drawStateLayer(interactionState, targetRadius, color)
-        }
-        val pressPosition = interactionState.interactionPositionFor(Interaction.Pressed)
-        if (pressPosition != null) {
-            if (currentPressPosition != pressPosition) {
-                addRipple(targetRadius, pressPosition)
-            }
-        } else {
-            removeRipple()
+            drawStateLayer(radius, color)
         }
         drawRipples(color)
     }
 
-    private fun ContentDrawScope.addRipple(targetRadius: Float, pressPosition: Offset) {
-        currentRipple?.finish()
-        val pxSize = Size(size.width, size.height)
-        val center = Offset(size.width / 2f, size.height / 2f)
-        val position = if (bounded) pressPosition else center
-        val ripple = RippleAnimation(pxSize, position, targetRadius, scope, bounded) { ripple ->
-            ripples.remove(ripple)
-            if (currentRipple == ripple) {
-                currentRipple = null
-            }
-        }
-        ripples.add(ripple)
-        currentPressPosition = pressPosition
-        currentRipple = ripple
+    suspend fun addRipple(interaction: PressInteraction.Press) {
+        // Finish existing ripples
+        ripples.forEach { (_, ripple) -> ripple.finish() }
+        val origin = if (bounded) interaction.pressPosition else null
+        val rippleAnimation = RippleAnimation(
+            origin = origin,
+            radius = radius,
+            bounded = bounded
+        )
+        ripples[interaction] = rippleAnimation
+        rippleAnimation.animate()
+        ripples.remove(interaction)
     }
 
-    private fun removeRipple() {
-        currentRipple?.finish()
-        currentRipple = null
-        currentPressPosition = null
+    suspend fun updateStateLayer(interaction: Interaction) {
+        stateLayer.handleInteraction(interaction)
+    }
+
+    fun removeRipple(interaction: PressInteraction.Press) {
+        ripples[interaction]?.finish()
     }
 
     private fun DrawScope.drawRipples(color: Color) {
-        ripples.fastForEach {
-            with(it) {
-                val alpha = rippleAlpha.pressedAlpha
+        ripples.forEach { (_, ripple) ->
+            with(ripple) {
+                val alpha = rippleAlpha.value.pressedAlpha
                 if (alpha != 0f) {
                     draw(color.copy(alpha = alpha))
                 }
@@ -217,32 +217,20 @@
         }
     }
 
-    private var timesRememembered = 0
-
-    override fun onRemembered() {
-        timesRememembered++
-    }
+    override fun onRemembered() {}
 
     override fun onForgotten() {
-        timesRememembered--
-        if (timesRememembered == 0) {
-            onDispose()
-        }
+        ripples.clear()
     }
 
     override fun onAbandoned() {
-        onDispose()
-    }
-
-    private fun onDispose() {
         ripples.clear()
-        currentRipple = null
     }
 }
 
 /**
  * Represents the layer underneath the press ripple, that displays an overlay for states such as
- * [Interaction.Dragged].
+ * [DragInteraction.Start].
  *
  * Typically, there should be both an 'incoming' and an 'outgoing' layer, so that when
  * transitioning between two states, the incoming of the new state, and the outgoing of the old
@@ -260,77 +248,62 @@
  * A state -> a different state = incoming transition for the new state
  * A state -> no state = outgoing transition for the old state
  *
- * @see IncomingStateLayerAnimationSpecs
- * @see OutgoingStateLayerAnimationSpecs
+ * @see incomingStateLayerAnimationSpecFor
+ * @see outgoingStateLayerAnimationSpecFor
  */
 private class StateLayer(
     private val bounded: Boolean,
-    private val rippleAlpha: RippleAlpha,
-    private val scope: CoroutineScope
+    // TODO: consider dynamically updating the alpha for existing interactions when rippleAlpha
+    // changes
+    private val rippleAlpha: State<RippleAlpha>
 ) {
     private val animatedAlpha = Animatable(0f)
-    private var previousInteractions: Set<Interaction> = emptySet()
-    private var lastDrawnInteraction: Interaction? = null
 
-    fun ContentDrawScope.drawStateLayer(
-        interactionState: InteractionState,
-        targetRadius: Float,
-        color: Color
-    ) {
-        val currentInteractions = interactionState.value
-        var handled = false
+    private val interactions: MutableList<Interaction> = mutableListOf()
+    private var currentInteraction: Interaction? = null
 
-        // Handle a new interaction, starting from the end as we care about the most recent
-        // interaction, not the oldest interaction.
-        for (interaction in currentInteractions.reversed()) {
-            // Stop looping if we have already moved to a new state
-            if (handled) break
-
-            // Pressed state is explicitly handled with a ripple animation, and not a state layer
-            if (interaction is Interaction.Pressed) continue
-
-            // Move to the next interaction if this interaction is not a new interaction
-            if (interaction in previousInteractions) continue
-
-            val targetAlpha = when (interaction) {
-                Interaction.Dragged -> rippleAlpha.draggedAlpha
-                else -> 0f
+    suspend fun handleInteraction(interaction: Interaction) {
+        // TODO: handle hover / focus states
+        when (interaction) {
+            is DragInteraction.Start -> {
+                interactions.add(interaction)
             }
-            // Move to the next interaction if this is not an interaction we show a state layer for
-            if (targetAlpha == 0f) continue
-
-            // TODO: consider defaults - these will be used for a custom Interaction that we are
-            // not aware of, but has an alpha that should be shown because of a custom RippleTheme.
-            val incomingAnimationSpec = IncomingStateLayerAnimationSpecs[interaction]
-                ?: TweenSpec(durationMillis = 15, easing = LinearEasing)
-
-            scope.launch {
-                animatedAlpha.animateTo(targetAlpha, incomingAnimationSpec)
+            is DragInteraction.Stop -> {
+                interactions.remove(interaction.start)
             }
-
-            lastDrawnInteraction = interaction
-            handled = true
+            is DragInteraction.Cancel -> {
+                interactions.remove(interaction.start)
+            }
+            else -> return
         }
 
-        // Clean up any stale interactions if we have not moved to a new interaction
-        if (!handled) {
-            val previousInteraction = lastDrawnInteraction
-            if (previousInteraction != null && previousInteraction !in currentInteractions) {
-                // TODO: consider defaults - these will be used for a custom Interaction that we are
-                // not aware of, but has an alpha that should be shown because of a custom
-                // RippleTheme.
-                val outgoingAnimationSpec = OutgoingStateLayerAnimationSpecs[previousInteraction]
-                    ?: TweenSpec(durationMillis = 15, easing = LinearEasing)
+        // The most recent interaction is the one we want to show
+        val newInteraction = interactions.lastOrNull()
 
-                scope.launch {
-                    animatedAlpha.animateTo(0f, outgoingAnimationSpec)
+        if (currentInteraction != newInteraction) {
+            if (newInteraction != null) {
+                val targetAlpha = when (interaction) {
+                    is DragInteraction.Start -> rippleAlpha.value.draggedAlpha
+                    else -> 0f
                 }
+                val incomingAnimationSpec = incomingStateLayerAnimationSpecFor(newInteraction)
 
-                lastDrawnInteraction = null
+                animatedAlpha.animateTo(targetAlpha, incomingAnimationSpec)
+            } else {
+                val outgoingAnimationSpec = outgoingStateLayerAnimationSpecFor(currentInteraction)
+
+                animatedAlpha.animateTo(0f, outgoingAnimationSpec)
             }
+            currentInteraction = newInteraction
         }
+    }
 
-        previousInteractions = currentInteractions
+    fun DrawScope.drawStateLayer(radius: Dp, color: Color) {
+        val targetRadius = if (radius.isUnspecified) {
+            getRippleEndRadius(bounded, size)
+        } else {
+            radius.toPx()
+        }
 
         val alpha = animatedAlpha.value
 
@@ -349,26 +322,33 @@
 }
 
 /**
- * [AnimationSpec]s used when transitioning to a new state, either from a previous state, or no
- * state.
+ * @return the [AnimationSpec] used when transitioning to [interaction], either from a previous
+ * state, or no state.
  *
  * TODO: handle hover / focus states
  */
-private val IncomingStateLayerAnimationSpecs: Map<Interaction, AnimationSpec<Float>> = mapOf(
-    Interaction.Dragged to TweenSpec(
-        durationMillis = 45,
-        easing = LinearEasing
-    )
-)
+private fun incomingStateLayerAnimationSpecFor(interaction: Interaction): AnimationSpec<Float> {
+    return if (interaction is DragInteraction.Start) {
+        TweenSpec(durationMillis = 45, easing = LinearEasing)
+    } else {
+        DefaultTweenSpec
+    }
+}
 
 /**
- * [AnimationSpec]s used when transitioning away from a state, to no state.
+ * @return the [AnimationSpec] used when transitioning away from [interaction], to no state.
  *
  * TODO: handle hover / focus states
  */
-private val OutgoingStateLayerAnimationSpecs: Map<Interaction, AnimationSpec<Float>> = mapOf(
-    Interaction.Dragged to TweenSpec(
-        durationMillis = 150,
-        easing = LinearEasing
-    )
-)
+private fun outgoingStateLayerAnimationSpecFor(interaction: Interaction?): AnimationSpec<Float> {
+    return if (interaction is DragInteraction.Start) {
+        TweenSpec(durationMillis = 150, easing = LinearEasing)
+    } else {
+        DefaultTweenSpec
+    }
+}
+
+/**
+ * Default / fallback [AnimationSpec].
+ */
+private val DefaultTweenSpec = TweenSpec<Float>(durationMillis = 15, easing = LinearEasing)
diff --git a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt
index 257d152..6005049 100644
--- a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt
+++ b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleAnimation.kt
@@ -19,7 +19,6 @@
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.FastOutSlowInEasing
 import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.VectorConverter
 import androidx.compose.animation.core.tween
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -30,18 +29,18 @@
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.drawscope.clipRect
 import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.CoroutineScope
+import androidx.compose.ui.unit.isUnspecified
+import androidx.compose.ui.util.lerp
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
-import kotlin.coroutines.Continuation
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
 import kotlin.math.max
 
 /**
  * [RippleAnimation]s are drawn as part of [Ripple] as a visual indicator for an
- * different [androidx.compose.foundation.Interaction]s.
+ * different [androidx.compose.foundation.interaction.Interaction]s.
  *
  * Use [androidx.compose.foundation.clickable] or [androidx.compose.foundation.indication] to add a
  * ripple to your component, which contains a RippleAnimation for pressed states, and
@@ -53,66 +52,54 @@
  * radius expanding from 60% of the final value. The ripple origin animates to the center of its
  * target layout for the bounded version and stays in the center for the unbounded one.
  *
- * @param size The size of the target layout.
- * @param startPosition The position the animation will start from.
+ * @param origin The position the animation will start from. If null the animation will start
+ * from the center of the layout bounds.
  * @param radius Effects grow up to this size.
- * @param clipped If true the effect should be clipped by the target layout bounds.
- * @param scope The coroutine scope used for suspending animations
- * @param onAnimationFinished Call when the effect animation has been finished.
+ * @param bounded If true the effect should be clipped by the target layout bounds.
  */
 internal class RippleAnimation(
-    size: Size,
-    startPosition: Offset,
-    radius: Float,
-    scope: CoroutineScope,
-    private val clipped: Boolean,
-    private val onAnimationFinished: (RippleAnimation) -> Unit
+    private var origin: Offset?,
+    private val radius: Dp,
+    private val bounded: Boolean
 ) {
-    private val startAlpha = 0f
-    private val startRadius = getRippleStartRadius(size)
+    private var startRadius: Float? = null
+    private var targetRadius: Float? = null
 
-    private val targetAlpha = 1f
-    private val targetRadius = radius
-    private val targetCenter = Offset(size.width / 2.0f, size.height / 2.0f)
+    private var targetCenter: Offset? = null
 
-    private val animatedAlpha = Animatable(startAlpha)
-    private val animatedRadius = Animatable(startRadius)
-    private val animatedCenter = Animatable(startPosition, Offset.VectorConverter)
+    private val animatedAlpha = Animatable(0f)
+    private val animatedRadiusPercent = Animatable(0f)
+    private val animatedCenterPercent = Animatable(0f)
 
-    private var finishContinuation: Continuation<Unit>? = null
+    private val finishSignalDeferred = CompletableDeferred<Unit>(null)
+
     private var finishedFadingIn by mutableStateOf(false)
     private var finishRequested by mutableStateOf(false)
 
-    init {
-        scope.launch {
-            fadeIn()
-            finishedFadingIn = true
-            // If we haven't been told to finish, wait until we have been
-            if (!finishRequested) {
-                suspendCoroutine<Unit> { finishContinuation = it }
-            }
-            fadeOut()
-            onAnimationFinished(this@RippleAnimation)
-        }
+    suspend fun animate() {
+        fadeIn()
+        finishedFadingIn = true
+        finishSignalDeferred.await()
+        fadeOut()
     }
 
     private suspend fun fadeIn() {
         coroutineScope {
             launch {
                 animatedAlpha.animateTo(
-                    targetAlpha,
+                    1f,
                     tween(durationMillis = FadeInDuration, easing = LinearEasing)
                 )
             }
             launch {
-                animatedRadius.animateTo(
-                    targetRadius,
+                animatedRadiusPercent.animateTo(
+                    1f,
                     tween(durationMillis = RadiusDuration, easing = FastOutSlowInEasing)
                 )
             }
             launch {
-                animatedCenter.animateTo(
-                    targetCenter,
+                animatedCenterPercent.animateTo(
+                    1f,
                     tween(durationMillis = RadiusDuration, easing = LinearEasing)
                 )
             }
@@ -132,10 +119,27 @@
 
     fun finish() {
         finishRequested = true
-        finishContinuation?.resume(Unit)
+        finishSignalDeferred.complete(Unit)
     }
 
     fun DrawScope.draw(color: Color) {
+        if (startRadius == null) {
+            startRadius = getRippleStartRadius(size)
+        }
+        if (targetRadius == null) {
+            targetRadius = if (radius.isUnspecified) {
+                getRippleEndRadius(bounded, size)
+            } else {
+                radius.toPx()
+            }
+        }
+        if (origin == null) {
+            origin = center
+        }
+        if (targetCenter == null) {
+            targetCenter = Offset(size.width / 2.0f, size.height / 2.0f)
+        }
+
         val alpha = if (finishRequested && !finishedFadingIn) {
             // If we are still fading-in we should immediately switch to the final alpha.
             1f
@@ -143,11 +147,14 @@
             animatedAlpha.value
         }
 
-        val radius = animatedRadius.value
-        val centerOffset = animatedCenter.value
+        val radius = lerp(startRadius!!, targetRadius!!, animatedRadiusPercent.value)
+        val centerOffset = Offset(
+            lerp(origin!!.x, targetCenter!!.x, animatedCenterPercent.value),
+            lerp(origin!!.y, targetCenter!!.y, animatedCenterPercent.value),
+        )
 
         val modulatedColor = color.copy(alpha = color.alpha * alpha)
-        if (clipped) {
+        if (bounded) {
             clipRect {
                 drawCircle(modulatedColor, radius, centerOffset)
             }
diff --git a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt
index 8e68bda..b1b1411 100644
--- a/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt
+++ b/compose/material/material-ripple/src/commonMain/kotlin/androidx/compose/material/ripple/RippleTheme.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.material.ripple
 
-import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.material.ripple.RippleTheme.Companion.defaultRippleAlpha
 import androidx.compose.material.ripple.RippleTheme.Companion.defaultRippleColor
 import androidx.compose.runtime.Composable
@@ -103,10 +103,10 @@
 /**
  * RippleAlpha defines the alpha of the ripple / state layer for different [Interaction]s.
  *
- * @property draggedAlpha the alpha used when the ripple is [Interaction.Dragged]
+ * @property draggedAlpha the alpha used when the ripple is dragged
  * @property focusedAlpha not currently supported
  * @property hoveredAlpha not currently supported
- * @property pressedAlpha the alpha used when the ripple is [Interaction.Pressed]
+ * @property pressedAlpha the alpha used when the ripple is pressed
  */
 @Immutable
 public class RippleAlpha(
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index 85c8461..039434f 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -11,7 +11,7 @@
 
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-jyMeD6A(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class AppBarDefaults {
@@ -103,7 +103,7 @@
 
   public final class BottomNavigationKt {
     method @androidx.compose.runtime.Composable public static void BottomNavigation-ye6PvEY(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-mT8lZtY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-g7W06kY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
   }
 
   public final class BottomSheetScaffoldDefaults {
@@ -181,13 +181,13 @@
   }
 
   @androidx.compose.runtime.Stable public interface ButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class ButtonKt {
-    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class CardKt {
@@ -206,8 +206,8 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
-    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.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
+    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.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -362,12 +362,12 @@
   }
 
   @androidx.compose.runtime.Stable public interface FloatingActionButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class FloatingActionButtonKt {
-    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-i36UMrA(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
-    method @androidx.compose.runtime.Composable public static void FloatingActionButton-lf3tHAI(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-opHSmBI(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton-n9X6i6U(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
@@ -377,8 +377,8 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class IconKt {
@@ -450,8 +450,8 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -480,7 +480,7 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.RadioButtonColors colors);
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.RadioButtonColors colors);
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -539,7 +539,7 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SliderColors colors);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SliderColors colors);
   }
 
   public interface SnackbarData {
@@ -620,7 +620,7 @@
 
   public final class SwipeableKt {
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-rEcnmuA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.InteractionState? interactionState, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
+    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-827DgyA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
@@ -661,12 +661,12 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SwitchColors colors);
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SwitchColors colors);
   }
 
   public final class TabKt {
-    method @androidx.compose.runtime.Composable public static void Tab-EwjEPwU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Tab-iV7aoUM(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-TC9MJzw(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-wUuQ7UU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Immutable public final class TabPosition {
@@ -700,8 +700,8 @@
   @androidx.compose.runtime.Stable public interface TextFieldColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.InteractionState interactionState);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.interaction.InteractionSource interactionSource);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> leadingIconColor(boolean enabled, boolean isError);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> placeholderColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean enabled);
@@ -725,8 +725,8 @@
   }
 
   public final class TextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material/material/api/public_plus_experimental_current.txt b/compose/material/material/api/public_plus_experimental_current.txt
index 85c8461..039434f 100644
--- a/compose/material/material/api/public_plus_experimental_current.txt
+++ b/compose/material/material/api/public_plus_experimental_current.txt
@@ -11,7 +11,7 @@
 
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-jyMeD6A(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class AppBarDefaults {
@@ -103,7 +103,7 @@
 
   public final class BottomNavigationKt {
     method @androidx.compose.runtime.Composable public static void BottomNavigation-ye6PvEY(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-mT8lZtY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-g7W06kY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
   }
 
   public final class BottomSheetScaffoldDefaults {
@@ -181,13 +181,13 @@
   }
 
   @androidx.compose.runtime.Stable public interface ButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class ButtonKt {
-    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class CardKt {
@@ -206,8 +206,8 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
-    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.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
+    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.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -362,12 +362,12 @@
   }
 
   @androidx.compose.runtime.Stable public interface FloatingActionButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class FloatingActionButtonKt {
-    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-i36UMrA(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
-    method @androidx.compose.runtime.Composable public static void FloatingActionButton-lf3tHAI(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-opHSmBI(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton-n9X6i6U(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
@@ -377,8 +377,8 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class IconKt {
@@ -450,8 +450,8 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -480,7 +480,7 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.RadioButtonColors colors);
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.RadioButtonColors colors);
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -539,7 +539,7 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SliderColors colors);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SliderColors colors);
   }
 
   public interface SnackbarData {
@@ -620,7 +620,7 @@
 
   public final class SwipeableKt {
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-rEcnmuA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.InteractionState? interactionState, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
+    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-827DgyA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
@@ -661,12 +661,12 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SwitchColors colors);
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SwitchColors colors);
   }
 
   public final class TabKt {
-    method @androidx.compose.runtime.Composable public static void Tab-EwjEPwU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Tab-iV7aoUM(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-TC9MJzw(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-wUuQ7UU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Immutable public final class TabPosition {
@@ -700,8 +700,8 @@
   @androidx.compose.runtime.Stable public interface TextFieldColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.InteractionState interactionState);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.interaction.InteractionSource interactionSource);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> leadingIconColor(boolean enabled, boolean isError);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> placeholderColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean enabled);
@@ -725,8 +725,8 @@
   }
 
   public final class TextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index 85c8461..039434f 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -11,7 +11,7 @@
 
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-jyMeD6A(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class AppBarDefaults {
@@ -103,7 +103,7 @@
 
   public final class BottomNavigationKt {
     method @androidx.compose.runtime.Composable public static void BottomNavigation-ye6PvEY(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-mT8lZtY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void BottomNavigationItem-g7W06kY(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
   }
 
   public final class BottomSheetScaffoldDefaults {
@@ -181,13 +181,13 @@
   }
 
   @androidx.compose.runtime.Stable public interface ButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(boolean enabled, androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class ButtonKt {
-    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void Button(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void OutlinedButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static inline void TextButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.ButtonElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.foundation.BorderStroke? border, optional androidx.compose.material.ButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
   }
 
   public final class CardKt {
@@ -206,8 +206,8 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
-    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.foundation.InteractionState interactionState, optional androidx.compose.material.CheckboxColors colors);
+    method @androidx.compose.runtime.Composable public static void Checkbox(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
+    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.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.CheckboxColors colors);
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -362,12 +362,12 @@
   }
 
   @androidx.compose.runtime.Stable public interface FloatingActionButtonElevation {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.unit.Dp> elevation(androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
   public final class FloatingActionButtonKt {
-    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-i36UMrA(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
-    method @androidx.compose.runtime.Composable public static void FloatingActionButton-lf3tHAI(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-opHSmBI(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation);
+    method @androidx.compose.runtime.Composable public static void FloatingActionButton-n9X6i6U(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional long backgroundColor, optional long contentColor, optional androidx.compose.material.FloatingActionButtonElevation elevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
@@ -377,8 +377,8 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class IconKt {
@@ -450,8 +450,8 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -480,7 +480,7 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.RadioButtonColors colors);
+    method @androidx.compose.runtime.Composable public static void RadioButton(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.RadioButtonColors colors);
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -539,7 +539,7 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SliderColors colors);
+    method @androidx.compose.runtime.Composable public static void Slider(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange, optional int steps, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onValueChangeFinished, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SliderColors colors);
   }
 
   public interface SnackbarData {
@@ -620,7 +620,7 @@
 
   public final class SwipeableKt {
     method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static <T> androidx.compose.material.SwipeableState<T> rememberSwipeableState(T initialValue, optional androidx.compose.animation.core.AnimationSpec<java.lang.Float> animationSpec, optional kotlin.jvm.functions.Function1<? super T,java.lang.Boolean> confirmStateChange);
-    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-rEcnmuA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.InteractionState? interactionState, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
+    method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable-827DgyA(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, androidx.compose.foundation.gestures.Orientation orientation, optional boolean enabled, optional boolean reverseDirection, optional androidx.compose.foundation.interaction.MutableInteractionSource? interactionSource, optional kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, optional androidx.compose.material.ResistanceConfig? resistance, optional float velocityThreshold);
   }
 
   @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public class SwipeableState<T> {
@@ -661,12 +661,12 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.material.SwitchColors colors);
+    method @androidx.compose.runtime.Composable public static void Switch(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material.SwitchColors colors);
   }
 
   public final class TabKt {
-    method @androidx.compose.runtime.Composable public static void Tab-EwjEPwU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void Tab-iV7aoUM(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.InteractionState interactionState, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-TC9MJzw(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
+    method @androidx.compose.runtime.Composable public static void Tab-wUuQ7UU(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
   }
 
   @androidx.compose.runtime.Immutable public final class TabPosition {
@@ -700,8 +700,8 @@
   @androidx.compose.runtime.Stable public interface TextFieldColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> backgroundColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.InteractionState interactionState);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.InteractionState interactionState);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
+    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean error, androidx.compose.foundation.interaction.InteractionSource interactionSource);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> leadingIconColor(boolean enabled, boolean isError);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> placeholderColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean enabled);
@@ -725,8 +725,8 @@
   }
 
   public final class TextFieldKt {
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
-    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.InteractionState interactionState, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
+    method @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 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 kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt b/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt
index df0166c..27debe0 100644
--- a/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt
+++ b/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/TopAppBar.kt
@@ -20,7 +20,7 @@
 import androidx.compose.animation.core.LinearEasing
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -77,7 +77,7 @@
                 .selectable(
                     selected = selected,
                     >
-                    interactionState = remember { InteractionState() },
+                    interactionSource = remember { MutableInteractionSource() },
                     indication = rememberRipple(bounded = false)
                 )
         ) {
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt
index c347707..f5801f5 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationScreenshotTest.kt
@@ -17,12 +17,14 @@
 package androidx.compose.material
 
 import android.os.Build
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
@@ -37,6 +39,8 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.screenshot.AndroidXScreenshotTestRule
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,18 +59,20 @@
 
     @Test
     fun lightTheme_defaultColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
-                DefaultBottomNavigation(interactionState)
+                scope = rememberCoroutineScope()
+                DefaultBottomNavigation(interactionSource)
             }
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "bottomNavigation_lightTheme_defaultColors"
         )
@@ -74,31 +80,36 @@
 
     @Test
     fun lightTheme_defaultColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
-                DefaultBottomNavigation(interactionState)
+                scope = rememberCoroutineScope()
+                DefaultBottomNavigation(interactionSource)
             }
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "bottomNavigation_lightTheme_defaultColors_pressed"
         )
     }
 
     @Test
     fun lightTheme_surfaceColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -107,7 +118,8 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "bottomNavigation_lightTheme_surfaceColors"
         )
@@ -115,12 +127,15 @@
 
     @Test
     fun lightTheme_surfaceColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -129,26 +144,29 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "bottomNavigation_lightTheme_surfaceColors_pressed"
         )
     }
 
     @Test
     fun darkTheme_defaultColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
-                DefaultBottomNavigation(interactionState)
+                scope = rememberCoroutineScope()
+                DefaultBottomNavigation(interactionSource)
             }
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "bottomNavigation_darkTheme_defaultColors"
         )
@@ -156,17 +174,21 @@
 
     @Test
     fun darkTheme_defaultColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
-                DefaultBottomNavigation(interactionState)
+                scope = rememberCoroutineScope()
+                DefaultBottomNavigation(interactionSource)
             }
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "bottomNavigation_darkTheme_defaultColors_pressed"
         )
     }
@@ -176,14 +198,15 @@
     // matches that use case.
     @Test
     fun darkTheme_surfaceColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -192,7 +215,8 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "bottomNavigation_darkTheme_surfaceColors"
         )
@@ -200,12 +224,15 @@
 
     @Test
     fun darkTheme_surfaceColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -214,22 +241,24 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "bottomNavigation_darkTheme_surfaceColors_pressed"
         )
     }
 
     @Test
     fun darkTheme_primaryColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.primary,
                     selectedContentColor = MaterialTheme.colors.onPrimary,
                     unselectedContentColor = MaterialTheme.colors.onPrimary
@@ -238,7 +267,8 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "bottomNavigation_darkTheme_primaryColors"
         )
@@ -246,12 +276,15 @@
 
     @Test
     fun darkTheme_primaryColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomBottomNavigation(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.primary,
                     selectedContentColor = MaterialTheme.colors.onPrimary,
                     unselectedContentColor = MaterialTheme.colors.onPrimary
@@ -260,8 +293,9 @@
         }
 
         assertBottomNavigationMatches(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "bottomNavigation_darkTheme_primaryColors_pressed"
         )
     }
@@ -269,12 +303,15 @@
     /**
      * Asserts that the BottomNavigation matches the screenshot with identifier [goldenIdentifier].
      *
-     * @param interactionState the [InteractionState] used for the first BottomNavigationItem
+     * @param scope [CoroutineScope] used to interact with [MutableInteractionSource]
+     * @param interactionSource the [MutableInteractionSource] used for the first
+     * BottomNavigationItem
      * @param interaction the [Interaction] to assert for, or `null` if no [Interaction].
      * @param goldenIdentifier the identifier for the corresponding screenshot
      */
     private fun assertBottomNavigationMatches(
-        interactionState: InteractionState,
+        scope: CoroutineScope,
+        interactionSource: MutableInteractionSource,
         interaction: Interaction? = null,
         goldenIdentifier: String
     ) {
@@ -282,12 +319,8 @@
 
         if (interaction != null) {
             // Start ripple
-            composeTestRule.runOnUiThread {
-                if (interaction is Interaction.Pressed) {
-                    interactionState.addInteraction(interaction, Offset(10f, 10f))
-                } else {
-                    interactionState.addInteraction(interaction)
-                }
+            scope.launch {
+                interactionSource.emit(interaction)
             }
 
             // Advance to somewhere in the middle of the animation for the ripple
@@ -306,12 +339,12 @@
  * Default colored [BottomNavigation] with three [BottomNavigationItem]s. The first
  * [BottomNavigationItem] is selected, and the rest are not.
  *
- * @param interactionState the [InteractionState] for the first [BottomNavigationItem], to control
- * its visual state.
+ * @param interactionSource the [MutableInteractionSource] for the first [BottomNavigationItem], to
+ * control its visual state.
  */
 @Composable
 private fun DefaultBottomNavigation(
-    interactionState: InteractionState
+    interactionSource: MutableInteractionSource
 ) {
     Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
         BottomNavigation {
@@ -319,7 +352,7 @@
                 icon = { Icon(Icons.Filled.Favorite, null) },
                 selected = true,
                 >
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
             BottomNavigationItem(
                 icon = { Icon(Icons.Filled.Favorite, null) },
@@ -339,8 +372,8 @@
  * Custom colored [BottomNavigation] with three [BottomNavigationItem]s. The first
  * [BottomNavigationItem] is selected, and the rest are not.
  *
- * @param interactionState the [InteractionState] for the first [BottomNavigationItem], to control
- * its visual state.
+ * @param interactionSource the [MutableInteractionSource] for the first [BottomNavigationItem], to
+ * control its visual state.
  * @param backgroundColor the backgroundColor of the [BottomNavigation]
  * @param selectedContentColor the content color for a selected [BottomNavigationItem] (first item)
  * @param unselectedContentColor the content color for an unselected [BottomNavigationItem] (second
@@ -348,7 +381,7 @@
  */
 @Composable
 private fun CustomBottomNavigation(
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     backgroundColor: Color,
     selectedContentColor: Color,
     unselectedContentColor: Color
@@ -362,7 +395,7 @@
                 icon = { Icon(Icons.Filled.Favorite, null) },
                 selected = true,
                 >
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 selectedContentColor = selectedContentColor,
                 unselectedContentColor = unselectedContentColor
             )
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
index a4a96ab..a69e05a 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/MaterialRippleThemeTest.kt
@@ -17,9 +17,11 @@
 package androidx.compose.material
 
 import android.os.Build
+import androidx.compose.foundation.interaction.DragInteraction
 import androidx.compose.foundation.Indication
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.indication
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
@@ -35,6 +37,7 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.ui.Alignment
@@ -45,7 +48,6 @@
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -56,6 +58,8 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.screenshot.AndroidXScreenshotTestRule
 import com.google.common.truth.Truth
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -67,7 +71,6 @@
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-@OptIn(ExperimentalMaterialApi::class, ExperimentalTestApi::class)
 class MaterialRippleThemeTest {
 
     @get:Rule
@@ -78,20 +81,21 @@
 
     @Test
     fun bounded_lightTheme_highLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_bounded_light_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
@@ -99,20 +103,21 @@
 
     @Test
     fun bounded_lightTheme_highLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_bounded_light_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
@@ -120,20 +125,21 @@
 
     @Test
     fun bounded_lightTheme_lowLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_bounded_light_lowluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
@@ -141,20 +147,21 @@
 
     @Test
     fun bounded_lightTheme_lowLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_bounded_light_lowluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
@@ -162,20 +169,21 @@
 
     @Test
     fun bounded_darkTheme_highLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_bounded_dark_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.10f)
         )
@@ -183,20 +191,21 @@
 
     @Test
     fun bounded_darkTheme_highLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_bounded_dark_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
@@ -204,20 +213,21 @@
 
     @Test
     fun bounded_darkTheme_lowLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_bounded_dark_lowluminance_pressed",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.10f)
@@ -226,20 +236,21 @@
 
     @Test
     fun bounded_darkTheme_lowLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = true,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_bounded_dark_lowluminance_dragged",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.08f)
@@ -248,20 +259,21 @@
 
     @Test
     fun unbounded_lightTheme_highLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_unbounded_light_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.24f)
         )
@@ -269,20 +281,21 @@
 
     @Test
     fun unbounded_lightTheme_highLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_unbounded_light_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.16f)
         )
@@ -290,20 +303,21 @@
 
     @Test
     fun unbounded_lightTheme_lowLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_unbounded_light_lowluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.12f)
         )
@@ -311,20 +325,21 @@
 
     @Test
     fun unbounded_lightTheme_lowLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = true,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_unbounded_light_lowluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
@@ -332,20 +347,21 @@
 
     @Test
     fun unbounded_darkTheme_highLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_unbounded_dark_highluminance_pressed",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.10f)
         )
@@ -353,20 +369,21 @@
 
     @Test
     fun unbounded_darkTheme_highLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.White
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_unbounded_dark_highluminance_dragged",
             calculateResultingRippleColor(contentColor, rippleOpacity = 0.08f)
         )
@@ -374,20 +391,21 @@
 
     @Test
     fun unbounded_darkTheme_lowLuminance_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_unbounded_dark_lowluminance_pressed",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.10f)
@@ -396,20 +414,21 @@
 
     @Test
     fun unbounded_darkTheme_lowLuminance_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
-        rule.setRippleContent(
-            interactionState = interactionState,
+        val scope = rule.setRippleContent(
+            interactionSource = interactionSource,
             bounded = false,
             lightTheme = false,
             contentColor = contentColor
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_unbounded_dark_lowluminance_dragged",
             // Low luminance content in dark theme should use a white ripple by default
             calculateResultingRippleColor(Color.White, rippleOpacity = 0.08f)
@@ -418,7 +437,7 @@
 
     @Test
     fun customRippleTheme_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
@@ -434,12 +453,15 @@
             override fun rippleAlpha() = rippleAlpha
         }
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme {
                 CompositionLocalProvider(LocalRippleTheme provides rippleTheme) {
                     Surface(contentColor = contentColor) {
                         Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
-                            RippleBox(interactionState, rememberRipple())
+                            RippleBox(interactionSource, rememberRipple())
                         }
                     }
                 }
@@ -452,8 +474,9 @@
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Pressed,
+            scope!!,
+            interactionSource,
+            PressInteraction.Press(Offset(10f, 10f)),
             "ripple_customtheme_pressed",
             expectedColor
         )
@@ -461,7 +484,7 @@
 
     @Test
     fun customRippleTheme_dragged() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val contentColor = Color.Black
 
@@ -476,12 +499,15 @@
             override fun rippleAlpha() = rippleAlpha
         }
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme {
                 CompositionLocalProvider(LocalRippleTheme provides rippleTheme) {
                     Surface(contentColor = contentColor) {
                         Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
-                            RippleBox(interactionState, rememberRipple())
+                            RippleBox(interactionSource, rememberRipple())
                         }
                     }
                 }
@@ -494,16 +520,17 @@
         )
 
         assertRippleMatches(
-            interactionState,
-            Interaction.Dragged,
+            scope!!,
+            interactionSource,
+            DragInteraction.Start(),
             "ripple_customtheme_dragged",
             expectedColor
         )
     }
 
     @Test
-    fun themeChangeDuringRipple() {
-        val interactionState = InteractionState()
+    fun themeChangeDuringRipple_dragged() {
+        val interactionSource = MutableInteractionSource()
 
         fun createRippleTheme(color: Color, alpha: Float) = object : RippleTheme {
             val rippleAlpha = RippleAlpha(alpha, alpha, alpha, alpha)
@@ -519,21 +546,100 @@
 
         var rippleTheme by mutableStateOf(createRippleTheme(initialColor, initialAlpha))
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme {
                 CompositionLocalProvider(LocalRippleTheme provides rippleTheme) {
                     Surface(contentColor = Color.Black) {
                         Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
-                            RippleBox(interactionState, rememberRipple())
+                            RippleBox(interactionSource, rememberRipple())
                         }
                     }
                 }
             }
         }
 
-        rule.runOnUiThread {
-            interactionState.addInteraction(Interaction.Pressed, Offset(10f, 10f))
+        rule.runOnIdle {
+            scope!!.launch {
+                interactionSource.emit(DragInteraction.Start())
+            }
         }
+        rule.waitForIdle()
+
+        with(rule.onNodeWithTag(Tag)) {
+            val centerPixel = captureToImage().asAndroidBitmap()
+                .run {
+                    getPixel(width / 2, height / 2)
+                }
+
+            val expectedColor =
+                calculateResultingRippleColor(initialColor, rippleOpacity = initialAlpha)
+
+            Truth.assertThat(Color(centerPixel)).isEqualTo(expectedColor)
+        }
+
+        val newColor = Color.Green
+        // TODO: changing alpha for existing state layers is not currently supported
+        val newAlpha = 0.5f
+
+        rule.runOnUiThread {
+            rippleTheme = createRippleTheme(newColor, newAlpha)
+        }
+
+        with(rule.onNodeWithTag(Tag)) {
+            val centerPixel = captureToImage().asAndroidBitmap()
+                .run {
+                    getPixel(width / 2, height / 2)
+                }
+
+            val expectedColor =
+                calculateResultingRippleColor(newColor, rippleOpacity = newAlpha)
+
+            Truth.assertThat(Color(centerPixel)).isEqualTo(expectedColor)
+        }
+    }
+
+    @Test
+    fun themeChangeDuringRipple_pressed() {
+        val interactionSource = MutableInteractionSource()
+
+        fun createRippleTheme(color: Color, alpha: Float) = object : RippleTheme {
+            val rippleAlpha = RippleAlpha(alpha, alpha, alpha, alpha)
+            @Composable
+            override fun defaultColor() = color
+
+            @Composable
+            override fun rippleAlpha() = rippleAlpha
+        }
+
+        val initialColor = Color.Red
+        val initialAlpha = 0.5f
+
+        var rippleTheme by mutableStateOf(createRippleTheme(initialColor, initialAlpha))
+
+        var scope: CoroutineScope? = null
+
+        rule.setContent {
+            scope = rememberCoroutineScope()
+            MaterialTheme {
+                CompositionLocalProvider(LocalRippleTheme provides rippleTheme) {
+                    Surface(contentColor = Color.Black) {
+                        Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+                            RippleBox(interactionSource, rememberRipple())
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.runOnIdle {
+            scope!!.launch {
+                interactionSource.emit(PressInteraction.Press(Offset.Zero))
+            }
+        }
+        rule.waitForIdle()
 
         with(rule.onNodeWithTag(Tag)) {
             val centerPixel = captureToImage().asAndroidBitmap()
@@ -569,7 +675,7 @@
 
     @Test
     fun contentColorProvidedAfterRememberRipple() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
 
         val alpha = 0.5f
         val rippleAlpha = RippleAlpha(alpha, alpha, alpha, alpha)
@@ -583,7 +689,10 @@
             override fun rippleAlpha() = rippleAlpha
         }
 
+        var scope: CoroutineScope? = null
+
         rule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme {
                 CompositionLocalProvider(LocalRippleTheme provides theme) {
                     Surface(contentColor = Color.Black) {
@@ -593,7 +702,7 @@
                             Surface(contentColor = expectedRippleColor) {
                                 // Ripple is used where contentColor is red, so the instance
                                 // should get the red color when it is created
-                                RippleBox(interactionState, ripple)
+                                RippleBox(interactionSource, ripple)
                             }
                         }
                     }
@@ -602,7 +711,9 @@
         }
 
         rule.runOnUiThread {
-            interactionState.addInteraction(Interaction.Pressed, Offset(10f, 10f))
+            scope!!.launch {
+                interactionSource.emit(PressInteraction.Press(Offset(10f, 10f)))
+            }
         }
 
         with(rule.onNodeWithTag(Tag)) {
@@ -622,14 +733,15 @@
      * Asserts that the ripple matches the screenshot with identifier [goldenIdentifier], and
      * that the resultant color of the ripple on screen matches [expectedCenterPixelColor].
      *
-     * @param interactionState the [InteractionState] driving the ripple
+     * @param interactionSource the [MutableInteractionSource] driving the ripple
      * @param interaction the [Interaction] to assert for
      * @param goldenIdentifier the identifier for the corresponding screenshot
      * @param expectedCenterPixelColor the expected color for the pixel at the center of the
      * [RippleBox]
      */
     private fun assertRippleMatches(
-        interactionState: InteractionState,
+        scope: CoroutineScope,
+        interactionSource: MutableInteractionSource,
         interaction: Interaction,
         goldenIdentifier: String,
         expectedCenterPixelColor: Color
@@ -637,12 +749,8 @@
         rule.mainClock.autoAdvance = false
 
         // Start ripple
-        rule.runOnUiThread {
-            if (interaction is Interaction.Pressed) {
-                interactionState.addInteraction(interaction, Offset(10f, 10f))
-            } else {
-                interactionState.addInteraction(interaction)
-            }
+        scope.launch {
+            interactionSource.emit(interaction)
         }
 
         // Advance to somewhere in the middle of the animation for a ripple, or at the end of a
@@ -674,11 +782,11 @@
  * Generic Button like component that allows injecting an [Indication] and also includes
  * padding around the rippled surface, so screenshots will include some dead space for clarity.
  *
- * @param interactionState the [InteractionState] that is used to drive the ripple state
+ * @param interactionSource the [MutableInteractionSource] that is used to drive the ripple state
  * @param ripple ripple [Indication] placed inside the surface
  */
 @Composable
-private fun RippleBox(interactionState: InteractionState, ripple: Indication) {
+private fun RippleBox(interactionSource: MutableInteractionSource, ripple: Indication) {
     Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
         Surface(
             Modifier.padding(25.dp),
@@ -686,7 +794,7 @@
         ) {
             Box(
                 Modifier.width(80.dp).height(50.dp).indication(
-                    interactionState = interactionState,
+                    interactionSource = interactionSource,
                     indication = ripple
                 )
             )
@@ -697,28 +805,33 @@
 /**
  * Sets the content to a [RippleBox] with a [MaterialTheme] and surrounding [Surface]
  *
- * @param interactionState [InteractionState] used to drive the ripple inside the [RippleBox]
+ * @param interactionSource [MutableInteractionSource] used to drive the ripple inside the [RippleBox]
  * @param bounded whether the ripple inside the [RippleBox] is bounded
  * @param lightTheme whether the theme is light or dark
  * @param contentColor the contentColor that will be used for the ripple color
  */
 private fun ComposeContentTestRule.setRippleContent(
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     bounded: Boolean,
     lightTheme: Boolean,
     contentColor: Color
-) {
+): CoroutineScope {
+    var scope: CoroutineScope? = null
+
     setContent {
+        scope = rememberCoroutineScope()
         val colors = if (lightTheme) lightColors() else darkColors()
 
         MaterialTheme(colors) {
             Surface(contentColor = contentColor) {
                 Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
-                    RippleBox(interactionState, rememberRipple(bounded))
+                    RippleBox(interactionSource, rememberRipple(bounded))
                 }
             }
         }
     }
+    waitForIdle()
+    return scope!!
 }
 
 /**
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
index da13cba..a3a0cfb 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SwipeableTest.kt
@@ -1558,7 +1558,7 @@
                 "orientation",
                 "enabled",
                 "reverseDirection",
-                "interactionState",
+                "interactionSource",
                 "thresholds",
                 "resistance",
                 "velocityThreshold"
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt
index 778b0ba..0ac6564 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/TabScreenshotTest.kt
@@ -17,10 +17,12 @@
 package androidx.compose.material
 
 import android.os.Build
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
@@ -35,6 +37,8 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.screenshot.AndroidXScreenshotTestRule
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -53,18 +57,20 @@
 
     @Test
     fun lightTheme_defaultColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme(lightColors()) {
-                DefaultTabs(interactionState)
+                DefaultTabs(interactionSource)
             }
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "tabs_lightTheme_defaultColors"
         )
@@ -72,31 +78,36 @@
 
     @Test
     fun lightTheme_defaultColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme(lightColors()) {
-                DefaultTabs(interactionState)
+                DefaultTabs(interactionSource)
             }
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "tabs_lightTheme_defaultColors_pressed"
         )
     }
 
     @Test
     fun lightTheme_surfaceColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -105,7 +116,8 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "tabs_lightTheme_surfaceColors"
         )
@@ -113,12 +125,15 @@
 
     @Test
     fun lightTheme_surfaceColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(lightColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -127,26 +142,29 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "tabs_lightTheme_surfaceColors_pressed"
         )
     }
 
     @Test
     fun darkTheme_defaultColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme(darkColors()) {
-                DefaultTabs(interactionState)
+                DefaultTabs(interactionSource)
             }
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "tabs_darkTheme_defaultColors"
         )
@@ -154,17 +172,21 @@
 
     @Test
     fun darkTheme_defaultColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
+            scope = rememberCoroutineScope()
             MaterialTheme(darkColors()) {
-                DefaultTabs(interactionState)
+                DefaultTabs(interactionSource)
             }
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "tabs_darkTheme_defaultColors_pressed"
         )
     }
@@ -174,14 +196,15 @@
     // matches that use case.
     @Test
     fun darkTheme_surfaceColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -190,7 +213,8 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "tabs_darkTheme_surfaceColors"
         )
@@ -198,12 +222,15 @@
 
     @Test
     fun darkTheme_surfaceColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.surface,
                     selectedContentColor = MaterialTheme.colors.primary,
                     unselectedContentColor = MaterialTheme.colors.onSurface
@@ -212,22 +239,24 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "tabs_darkTheme_surfaceColors_pressed"
         )
     }
 
     @Test
     fun darkTheme_primaryColors() {
-        val interactionState = InteractionState().apply {
-            addInteraction(Interaction.Pressed)
-        }
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.primary,
                     selectedContentColor = MaterialTheme.colors.onPrimary,
                     unselectedContentColor = MaterialTheme.colors.onPrimary
@@ -236,7 +265,8 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
+            scope = scope!!,
+            interactionSource = interactionSource,
             interaction = null,
             goldenIdentifier = "tabs_darkTheme_primaryColors"
         )
@@ -244,12 +274,15 @@
 
     @Test
     fun darkTheme_primaryColors_pressed() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         composeTestRule.setContent {
             MaterialTheme(darkColors()) {
+                scope = rememberCoroutineScope()
                 CustomTabs(
-                    interactionState,
+                    interactionSource,
                     backgroundColor = MaterialTheme.colors.primary,
                     selectedContentColor = MaterialTheme.colors.onPrimary,
                     unselectedContentColor = MaterialTheme.colors.onPrimary
@@ -258,8 +291,9 @@
         }
 
         assertTabsMatch(
-            interactionState = interactionState,
-            interaction = Interaction.Pressed,
+            scope = scope!!,
+            interactionSource = interactionSource,
+            interaction = PressInteraction.Press(Offset(10f, 10f)),
             goldenIdentifier = "tabs_darkTheme_primaryColors_pressed"
         )
     }
@@ -267,12 +301,13 @@
     /**
      * Asserts that the tabs match the screenshot with identifier [goldenIdentifier].
      *
-     * @param interactionState the [InteractionState] used for the first Tab
+     * @param interactionSource the [MutableInteractionSource] used for the first Tab
      * @param interaction the [Interaction] to assert for, or `null` if no [Interaction].
      * @param goldenIdentifier the identifier for the corresponding screenshot
      */
     private fun assertTabsMatch(
-        interactionState: InteractionState,
+        scope: CoroutineScope,
+        interactionSource: MutableInteractionSource,
         interaction: Interaction? = null,
         goldenIdentifier: String
     ) {
@@ -280,12 +315,8 @@
 
         if (interaction != null) {
             // Start ripple
-            composeTestRule.runOnUiThread {
-                if (interaction is Interaction.Pressed) {
-                    interactionState.addInteraction(interaction, Offset(10f, 10f))
-                } else {
-                    interactionState.addInteraction(interaction)
-                }
+            scope.launch {
+                interactionSource.emit(interaction)
             }
 
             // Advance to somewhere in the middle of the animation for the ripple
@@ -303,18 +334,19 @@
 /**
  * Default colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
  *
- * @param interactionState the [InteractionState] for the first [Tab], to control its visual state.
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
  */
 @Composable
 private fun DefaultTabs(
-    interactionState: InteractionState
+    interactionSource: MutableInteractionSource
 ) {
     Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
         TabRow(selectedTabIndex = 0) {
             Tab(
                 text = { Text("TAB") },
                 selected = true,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 >
             )
             Tab(
@@ -334,14 +366,15 @@
 /**
  * Custom colored [TabRow] with three [Tab]s. The first [Tab] is selected, and the rest are not.
  *
- * @param interactionState the [InteractionState] for the first [Tab], to control its visual state.
+ * @param interactionSource the [MutableInteractionSource] for the first [Tab], to control its
+ * visual state.
  * @param backgroundColor the backgroundColor of the [TabRow]
  * @param selectedContentColor the content color for a selected [Tab] (first tab)
  * @param unselectedContentColor the content color for an unselected [Tab] (second and third tabs)
  */
 @Composable
 private fun CustomTabs(
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     backgroundColor: Color,
     selectedContentColor: Color,
     unselectedContentColor: Color
@@ -354,7 +387,7 @@
             Tab(
                 text = { Text("TAB") },
                 selected = true,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 selectedContentColor = selectedContentColor,
                 unselectedContentColor = unselectedContentColor,
                 >
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index ff8231dbc..a227236 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -20,8 +20,9 @@
 import android.os.Build
 import android.view.View
 import android.view.inputmethod.InputMethodManager
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -47,6 +48,7 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.testutils.assertShape
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
@@ -92,6 +94,9 @@
 import com.nhaarman.mockitokotlin2.eq
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.verify
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -156,63 +161,99 @@
     fun testTextFields_singleFocus() {
         val textField1Tag = "TextField1"
         val textField2Tag = "TextField2"
-        val interactionState1 = InteractionState()
-        val interactionState2 = InteractionState()
+        val interactionSource1 = MutableInteractionSource()
+        val interactionSource2 = MutableInteractionSource()
+
+        var scope: CoroutineScope? = null
 
         rule.setMaterialContent {
+            scope = rememberCoroutineScope()
             Column {
                 TextField(
                     modifier = Modifier.testTag(textField1Tag),
                     value = "input1",
                     >
                     label = {},
-                    interactionState = interactionState1
+                    interactionSource = interactionSource1
                 )
                 TextField(
                     modifier = Modifier.testTag(textField2Tag),
                     value = "input2",
                     >
                     label = {},
-                    interactionState = interactionState2
+                    interactionSource = interactionSource2
                 )
             }
         }
 
+        val interactions1 = mutableListOf<Interaction>()
+        val interactions2 = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource1.interactions.collect { interactions1.add(it) }
+        }
+        scope!!.launch {
+            interactionSource2.interactions.collect { interactions2.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions1).isEmpty()
+            assertThat(interactions2).isEmpty()
+        }
+
         rule.onNodeWithTag(textField1Tag).performClick()
 
         rule.runOnIdle {
-            assertThat(interactionState1.contains(Interaction.Focused)).isTrue()
-            assertThat(interactionState2.contains(Interaction.Focused)).isFalse()
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions1.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
+            assertThat(interactions2).isEmpty()
         }
 
         rule.onNodeWithTag(textField2Tag).performClick()
 
         rule.runOnIdle {
-            assertThat(interactionState1.contains(Interaction.Focused)).isFalse()
-            assertThat(interactionState2.contains(Interaction.Focused)).isTrue()
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions1.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
+            assertThat(interactions1.filterIsInstance<FocusInteraction.Unfocus>()).hasSize(1)
+            assertThat(interactions2.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
+            assertThat(interactions2.filterIsInstance<FocusInteraction.Unfocus>()).isEmpty()
         }
     }
 
     @Test
     fun testTextField_getFocus_whenClickedOnSurfaceArea() {
-        val interactionState = InteractionState()
+        val interactionSource = MutableInteractionSource()
+        var scope: CoroutineScope? = null
+
         rule.setMaterialContent {
+            scope = rememberCoroutineScope()
             TextField(
                 modifier = Modifier.testTag(TextfieldTag),
                 value = "input",
                 >
                 label = {},
-                interactionState = interactionState
+                interactionSource = interactionSource
             )
         }
 
+        val interactions = mutableListOf<Interaction>()
+
+        scope!!.launch {
+            interactionSource.interactions.collect { interactions.add(it) }
+        }
+
+        rule.runOnIdle {
+            assertThat(interactions).isEmpty()
+        }
+
         // Click on (2, 2) which is Surface area and outside input area
         rule.onNodeWithTag(TextfieldTag).performGesture {
             click(Offset(2f, 2f))
         }
 
-        rule.runOnIdleWithDensity {
-            assertThat(interactionState.contains(Interaction.Focused)).isTrue()
+        rule.runOnIdle {
+            // Not asserting total size as we have other interactions here too
+            assertThat(interactions.filterIsInstance<FocusInteraction.Focus>()).hasSize(1)
         }
     }
 
@@ -879,7 +920,6 @@
     @LargeTest
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     fun testTextField_alphaNotApplied_toCustomBackgroundColorAndTransparentColors() {
-        val interactionState = InteractionState()
 
         rule.setMaterialContent {
             Box(Modifier.background(color = Color.White)) {
@@ -895,7 +935,6 @@
                     trailingIcon = {
                         Icon(Icons.Default.Favorite, null, tint = Color.Transparent)
                     },
-                    interactionState = interactionState,
                     colors = TextFieldDefaults.textFieldColors(
                         backgroundColor = Color.Blue,
                         focusedIndicatorColor = Color.Transparent,
@@ -921,9 +960,6 @@
             )
 
         rule.onNodeWithTag(TextfieldTag).performClick()
-        rule.runOnIdle {
-            assertThat(interactionState.contains(Interaction.Focused)).isTrue()
-        }
 
         rule.onNodeWithTag(TextfieldTag)
             .captureToImage()
diff --git a/compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt
index 8622f56..546a3b91 100644
--- a/compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt
+++ b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/AndroidMenu.android.kt
@@ -17,12 +17,12 @@
 package androidx.compose.material
 
 import androidx.compose.animation.core.MutableTransitionState
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.RowScope
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
@@ -113,10 +113,10 @@
  * @param enabled Controls the enabled state of the menu item - when `false`, the menu item
  * will not be clickable and [onClick] will not be invoked
  * @param contentPadding the padding applied to the content of this menu item
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this DropdownMenuItem. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this DropdownMenuItem in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this DropdownMenuItem. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this DropdownMenuItem in different [Interaction]s.
  */
 @Composable
 fun DropdownMenuItem(
@@ -124,7 +124,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable RowScope.() -> Unit
 ) {
     DropdownMenuItemContent(
@@ -132,7 +132,7 @@
         modifier = modifier,
         enabled = enabled,
         contentPadding = contentPadding,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         content = content
     )
 }
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
index dd0b677..eb184b3 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
@@ -20,8 +20,8 @@
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.animation.core.VectorizedAnimationSpec
 import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
@@ -132,10 +132,10 @@
  * @param label optional text label for this item
  * @param alwaysShowLabel whether to always show the label for this item. If false, the label will
  * only be shown when this item is selected.
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this BottomNavigationItem. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this BottomNavigationItem in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this BottomNavigationItem. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this BottomNavigationItem in different [Interaction]s.
  * @param selectedContentColor the color of the text label and icon when this item is selected,
  * and the color of the ripple.
  * @param unselectedContentColor the color of the text label and icon when this item is not selected
@@ -149,7 +149,7 @@
     enabled: Boolean = true,
     label: @Composable (() -> Unit)? = null,
     alwaysShowLabel: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     selectedContentColor: Color = LocalContentColor.current,
     unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)
 ) {
@@ -171,7 +171,7 @@
                 >
                 enabled = enabled,
                 role = Role.Tab,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = ripple
             )
             .weight(1f),
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
index d684b53..60db864 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Button.kt
@@ -21,8 +21,10 @@
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.VectorConverter
 import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.indication
 import androidx.compose.foundation.layout.Arrangement
@@ -33,22 +35,25 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
 
 /**
  * Material Design implementation of a
@@ -76,11 +81,10 @@
  * @param modifier Modifier to be applied to the button
  * @param enabled Controls the enabled state of the button. When `false`, this button will not
  * be clickable
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Button. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this Button
- * in different [Interaction]s, such as customizing how the [elevation] of this Button changes when
- * it is [Interaction.Pressed].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Button. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Button in different [Interaction]s.
  * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
  * states. This controls the size of the shadow below the button. Pass `null` here to disable
  * elevation for this button. See [ButtonDefaults.elevation].
@@ -95,7 +99,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     elevation: ButtonElevation? = ButtonDefaults.elevation(),
     shape: Shape = MaterialTheme.shapes.small,
     border: BorderStroke? = null,
@@ -113,12 +117,12 @@
         color = colors.backgroundColor(enabled).value,
         contentColor = contentColor.copy(alpha = 1f),
         border = border,
-        elevation = elevation?.elevation(enabled, interactionState)?.value ?: 0.dp,
+        elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
         modifier = modifier.clickable(
             >
             enabled = enabled,
             role = Role.Button,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             indication = null
         )
     ) {
@@ -132,7 +136,7 @@
                             minWidth = ButtonDefaults.MinWidth,
                             minHeight = ButtonDefaults.MinHeight
                         )
-                        .indication(interactionState, rememberRipple())
+                        .indication(interactionSource, rememberRipple())
                         .padding(contentPadding),
                     horizontalArrangement = Arrangement.Center,
                     verticalAlignment = Alignment.CenterVertically,
@@ -167,11 +171,10 @@
  * @param modifier Modifier to be applied to the button
  * @param enabled Controls the enabled state of the button. When `false`, this button will not
  * be clickable
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Button. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this Button
- * in different [Interaction]s, such as customizing how the [elevation] of this Button changes when
- * it is [Interaction.Pressed].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Button. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Button in different [Interaction]s.
  * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
  * states. An OutlinedButton typically has no elevation, see [Button] for a button with elevation.
  * @param shape Defines the button's shape as well as its shadow
@@ -185,7 +188,7 @@
     noinline onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     elevation: ButtonElevation? = null,
     shape: Shape = MaterialTheme.shapes.small,
     border: BorderStroke? = ButtonDefaults.outlinedBorder,
@@ -196,7 +199,7 @@
     >
     modifier = modifier,
     enabled = enabled,
-    interactionState = interactionState,
+    interactionSource = interactionSource,
     elevation = elevation,
     shape = shape,
     border = border,
@@ -226,11 +229,10 @@
  * @param modifier Modifier to be applied to the button
  * @param enabled Controls the enabled state of the button. When `false`, this button will not
  * be clickable
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Button. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this Button
- * in different [Interaction]s, such as customizing how the [elevation] of this Button changes when
- * it is [Interaction.Pressed].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Button. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Button in different [Interaction]s.
  * @param elevation [ButtonElevation] used to resolve the elevation for this button in different
  * states. A TextButton typically has no elevation, see [Button] for a button with elevation.
  * @param shape Defines the button's shape as well as its shadow
@@ -244,7 +246,7 @@
     noinline onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     elevation: ButtonElevation? = null,
     shape: Shape = MaterialTheme.shapes.small,
     border: BorderStroke? = null,
@@ -255,7 +257,7 @@
     >
     modifier = modifier,
     enabled = enabled,
-    interactionState = interactionState,
+    interactionSource = interactionSource,
     elevation = elevation,
     shape = shape,
     border = border,
@@ -272,13 +274,14 @@
 @Stable
 interface ButtonElevation {
     /**
-     * Represents the elevation used in a button, depending on [enabled] and [interactionState].
+     * Represents the elevation used in a button, depending on [enabled] and
+     * [interactionSource].
      *
      * @param enabled whether the button is enabled
-     * @param interactionState the [InteractionState] for this button
+     * @param interactionSource the [InteractionSource] for this button
      */
     @Composable
-    fun elevation(enabled: Boolean, interactionState: InteractionState): State<Dp>
+    fun elevation(enabled: Boolean, interactionSource: InteractionSource): State<Dp>
 }
 
 /**
@@ -359,7 +362,7 @@
      * @param defaultElevation the elevation to use when the [Button] is enabled, and has no
      * other [Interaction]s.
      * @param pressedElevation the elevation to use when the [Button] is enabled and
-     * is [Interaction.Pressed].
+     * is pressed.
      * @param disabledElevation the elevation to use when the [Button] is not enabled.
      */
     @Composable
@@ -487,16 +490,31 @@
     private val disabledElevation: Dp,
 ) : ButtonElevation {
     @Composable
-    override fun elevation(enabled: Boolean, interactionState: InteractionState): State<Dp> {
-        val interaction = interactionState.value.lastOrNull {
-            it is Interaction.Pressed
+    override fun elevation(enabled: Boolean, interactionSource: InteractionSource): State<Dp> {
+        val interactions = remember { mutableStateListOf<Interaction>() }
+        LaunchedEffect(interactionSource) {
+            interactionSource.interactions.collect { interaction ->
+                when (interaction) {
+                    is PressInteraction.Press -> {
+                        interactions.add(interaction)
+                    }
+                    is PressInteraction.Release -> {
+                        interactions.remove(interaction.press)
+                    }
+                    is PressInteraction.Cancel -> {
+                        interactions.remove(interaction.press)
+                    }
+                }
+            }
         }
 
+        val interaction = interactions.lastOrNull()
+
         val target = if (!enabled) {
             disabledElevation
         } else {
             when (interaction) {
-                Interaction.Pressed -> pressedElevation
+                is PressInteraction.Press -> pressedElevation
                 else -> defaultElevation
             }
         }
@@ -511,7 +529,7 @@
         } else {
             LaunchedEffect(target) {
                 val lastInteraction = when (animatable.targetValue) {
-                    pressedElevation -> Interaction.Pressed
+                    pressedElevation -> PressInteraction.Press(Offset.Zero)
                     else -> null
                 }
                 animatable.animateElevation(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
index fe4f57e..32a9684 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
@@ -23,8 +23,8 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.wrapContentSize
@@ -69,10 +69,10 @@
  * @param modifier Modifier to be applied to the layout of the checkbox
  * @param enabled enabled whether or not this [Checkbox] will handle input events and appear
  * enabled for semantics purposes
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Checkbox. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this Checkbox in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Checkbox. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Checkbox in different [Interaction]s.
  * @param colors [CheckboxColors] that will be used to determine the color of the checkmark / box
  * / border in different states. See [CheckboxDefaults.colors].
  */
@@ -82,13 +82,13 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: CheckboxColors = CheckboxDefaults.colors()
 ) {
     TriStateCheckbox(
         state = ToggleableState(checked),
          onCheckedChange(!checked) },
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         enabled = enabled,
         colors = colors,
         modifier = modifier
@@ -112,10 +112,10 @@
  * @param modifier Modifier to be applied to the layout of the checkbox
  * @param enabled whether or not this [TriStateCheckbox] will handle input events and
  * appear enabled for semantics purposes
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this TriStateCheckbox. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this TriStateCheckbox in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this TriStateCheckbox. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this TriStateCheckbox in different [Interaction]s.
  * @param colors [CheckboxColors] that will be used to determine the color of the checkmark / box
  * / border in different states. See [CheckboxDefaults.colors].
  */
@@ -125,7 +125,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: CheckboxColors = CheckboxDefaults.colors()
 ) {
     CheckboxImpl(
@@ -137,7 +137,7 @@
                 >
                 enabled = enabled,
                 role = Role.Checkbox,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = rememberRipple(
                     bounded = false,
                     radius = CheckboxRippleRadius
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt
index 8928ce2..1a8d1e1 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Elevation.kt
@@ -21,7 +21,9 @@
 import androidx.compose.animation.core.CubicBezierEasing
 import androidx.compose.animation.core.FastOutSlowInEasing
 import androidx.compose.animation.core.TweenSpec
-import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.ui.unit.Dp
 
 /**
@@ -34,7 +36,7 @@
  * desired for the [to] state.
  * @param from the previous [Interaction] that was used to calculate elevation. `null` if there
  * was no previous [Interaction], such as when the component is in its default state.
- * @param to the [Interaction] that this component is moving to, such as [Interaction.Pressed]
+ * @param to the [Interaction] that this component is moving to, such as [PressInteraction.Press]
  * when this component is being pressed. `null` if this component is moving back to its default
  * state.
  */
@@ -75,8 +77,8 @@
      */
     fun incomingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
         return when (interaction) {
-            is Interaction.Pressed -> DefaultIncomingSpec
-            is Interaction.Dragged -> DefaultIncomingSpec
+            is PressInteraction.Press -> DefaultIncomingSpec
+            is DragInteraction.Start -> DefaultIncomingSpec
             else -> null
         }
     }
@@ -89,8 +91,8 @@
      */
     fun outgoingAnimationSpecForInteraction(interaction: Interaction): AnimationSpec<Dp>? {
         return when (interaction) {
-            is Interaction.Pressed -> DefaultOutgoingSpec
-            is Interaction.Dragged -> DefaultOutgoingSpec
+            is PressInteraction.Press -> DefaultOutgoingSpec
+            is DragInteraction.Start -> DefaultOutgoingSpec
             // TODO: use [HoveredOutgoingSpec] when hovered
             else -> null
         }
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
index 98fd3dd..5420d3c3 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/FloatingActionButton.kt
@@ -18,8 +18,10 @@
 
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.VectorConverter
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.indication
 import androidx.compose.foundation.layout.Box
@@ -32,18 +34,21 @@
 import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
 
 /**
  * A floating action button (FAB) is a button that represents the primary action of a screen.
@@ -57,11 +62,10 @@
  * @param onClick will be called when user clicked on this FAB. The FAB will be disabled
  * when it is null.
  * @param modifier [Modifier] to be applied to this FAB.
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this FAB. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this FAB
- * in different [Interaction]s, such as customizing how the [elevation] of this FAB changes when
- * it is [Interaction.Pressed].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this FAB. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this FAB in different [Interaction]s.
  * @param shape The [Shape] of this FAB
  * @param backgroundColor The background color. Use [Color.Transparent] to have no color
  * @param contentColor The preferred content color for content inside this FAB
@@ -73,7 +77,7 @@
 fun FloatingActionButton(
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
     backgroundColor: Color = MaterialTheme.colors.secondary,
     contentColor: Color = contentColorFor(backgroundColor),
@@ -87,20 +91,20 @@
         modifier = modifier.clickable(
             >
             role = Role.Button,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             indication = null
         ),
         shape = shape,
         color = backgroundColor,
         contentColor = contentColor,
-        elevation = elevation.elevation(interactionState).value
+        elevation = elevation.elevation(interactionSource).value
     ) {
         CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
             ProvideTextStyle(MaterialTheme.typography.button) {
                 Box(
                     modifier = Modifier
                         .defaultMinSize(minWidth = FabSize, minHeight = FabSize)
-                        .indication(interactionState, rememberRipple()),
+                        .indication(interactionSource, rememberRipple()),
                     contentAlignment = Alignment.Center
                 ) { content() }
             }
@@ -128,11 +132,10 @@
  * @param modifier [Modifier] to be applied to this FAB
  * @param icon Optional icon for this FAB, typically this will be a
  * [Icon].
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this FAB. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this FAB
- * in different [Interaction]s, such as customizing how the [elevation] of this FAB changes when
- * it is [Interaction.Pressed].
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this FAB. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this FAB in different [Interaction]s.
  * @param shape The [Shape] of this FAB
  * @param backgroundColor The background color. Use [Color.Transparent] to have no color
  * @param contentColor The preferred content color. Will be used by text and iconography
@@ -145,7 +148,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     icon: @Composable (() -> Unit)? = null,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
     backgroundColor: Color = MaterialTheme.colors.secondary,
     contentColor: Color = contentColorFor(backgroundColor),
@@ -157,7 +160,7 @@
             minHeight = ExtendedFabSize
         ),
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         shape = shape,
         backgroundColor = backgroundColor,
         contentColor = contentColor,
@@ -192,12 +195,13 @@
 @Stable
 interface FloatingActionButtonElevation {
     /**
-     * Represents the elevation used in a floating action button, depending on [interactionState].
+     * Represents the elevation used in a floating action button, depending on
+     * [interactionSource].
      *
-     * @param interactionState the [InteractionState] for this floating action button
+     * @param interactionSource the [InteractionSource] for this floating action button
      */
     @Composable
-    fun elevation(interactionState: InteractionState): State<Dp>
+    fun elevation(interactionSource: InteractionSource): State<Dp>
 }
 
 /**
@@ -212,7 +216,7 @@
      * @param defaultElevation the elevation to use when the [FloatingActionButton] has no
      * [Interaction]s
      * @param pressedElevation the elevation to use when the [FloatingActionButton] is
-     * [Interaction.Pressed].
+     * pressed.
      */
     @Composable
     fun elevation(
@@ -239,13 +243,28 @@
     private val pressedElevation: Dp,
 ) : FloatingActionButtonElevation {
     @Composable
-    override fun elevation(interactionState: InteractionState): State<Dp> {
-        val interaction = interactionState.value.lastOrNull {
-            it is Interaction.Pressed
+    override fun elevation(interactionSource: InteractionSource): State<Dp> {
+        val interactions = remember { mutableStateListOf<Interaction>() }
+        LaunchedEffect(interactionSource) {
+            interactionSource.interactions.collect { interaction ->
+                when (interaction) {
+                    is PressInteraction.Press -> {
+                        interactions.add(interaction)
+                    }
+                    is PressInteraction.Release -> {
+                        interactions.remove(interaction.press)
+                    }
+                    is PressInteraction.Cancel -> {
+                        interactions.remove(interaction.press)
+                    }
+                }
+            }
         }
 
+        val interaction = interactions.lastOrNull()
+
         val target = when (interaction) {
-            Interaction.Pressed -> pressedElevation
+            is PressInteraction.Press -> pressedElevation
             else -> defaultElevation
         }
 
@@ -253,7 +272,7 @@
 
         LaunchedEffect(target) {
             val lastInteraction = when (animatable.targetValue) {
-                pressedElevation -> Interaction.Pressed
+                pressedElevation -> PressInteraction.Press(Offset.Zero)
                 else -> null
             }
             animatable.animateElevation(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
index 56b7f40..7abb824 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
@@ -16,8 +16,8 @@
 
 package androidx.compose.material
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.size
@@ -48,10 +48,10 @@
  * @param modifier optional [Modifier] for this IconButton
  * @param enabled whether or not this IconButton will handle input events and appear enabled for
  * semantics purposes
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this IconButton. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this IconButton in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this IconButton. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this IconButton in different [Interaction]s.
  * @param content the content (icon) to be drawn inside the IconButton. This is typically an
  * [Icon].
  */
@@ -60,7 +60,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable () -> Unit
 ) {
     Box(
@@ -69,7 +69,7 @@
                 >
                 enabled = enabled,
                 role = Role.Button,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = rememberRipple(bounded = false, radius = RippleRadius)
             )
             .then(IconButtonSizeModifier),
@@ -88,10 +88,10 @@
  * @param modifier optional [Modifier] for this IconToggleButton
  * @param enabled enabled whether or not this [IconToggleButton] will handle input events and appear
  * enabled for semantics purposes
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this IconToggleButton. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this IconToggleButton in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this IconToggleButton. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this IconToggleButton in different [Interaction]s.
  * @param content the content (icon) to be drawn inside the IconToggleButton. This is typically an
  * [Icon].
  */
@@ -101,7 +101,7 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable () -> Unit
 ) {
     Box(
@@ -110,7 +110,7 @@
             >
             enabled = enabled,
             role = Role.Checkbox,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
             indication = rememberRipple(bounded = false, radius = RippleRadius)
         ).then(IconButtonSizeModifier),
         contentAlignment = Alignment.Center
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
index b4c0338..5bb14b2 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
@@ -21,7 +21,7 @@
 import androidx.compose.animation.core.animateFloat
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
@@ -38,8 +38,8 @@
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.ripple.rememberRipple
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.remember
@@ -49,8 +49,8 @@
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.DpOffset
-import androidx.compose.ui.unit.IntRect
 import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
@@ -140,7 +140,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable RowScope.() -> Unit
 ) {
     // TODO(popam, b/156911853): investigate replacing this Row with ListItem
@@ -149,7 +149,7 @@
             .clickable(
                 enabled = enabled,
                 >
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = rememberRipple(true)
             )
             .fillMaxWidth()
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
index 78d4974..0a5b9f4 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
@@ -16,8 +16,8 @@
 
 package androidx.compose.material
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.defaultMinSize
 import androidx.compose.foundation.layout.padding
@@ -112,10 +112,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this OutlinedTextField. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this OutlinedTextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this OutlinedTextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this OutlinedTextField in different [Interaction]s.
  * @param colors [TextFieldColors] that will be used to resolve color of the text and content
  * (including label, placeholder, leading and trailing icons, border) for this text field in
  * different states. See [TextFieldDefaults.outlinedTextFieldColors]
@@ -139,7 +139,7 @@
     singleLine: Boolean = false,
     maxLines: Int = Int.MAX_VALUE,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
 ) {
     var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) }
@@ -168,7 +168,7 @@
         keyboardActions = keyboardActions,
         maxLines = maxLines,
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         colors = colors
     )
 }
@@ -228,10 +228,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this OutlinedTextField. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this OutlinedTextField in different [Interaction]s
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this OutlinedTextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this OutlinedTextField in different [Interaction]s.
  * @param colors [TextFieldColors] that will be used to resolve color of the text and content
  * (including label, placeholder, leading and trailing icons, border) for this text field in
  * different states. See [TextFieldDefaults.outlinedTextFieldColors]
@@ -255,7 +255,7 @@
     singleLine: Boolean = false,
     maxLines: Int = Int.MAX_VALUE,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
 ) {
     TextFieldImpl(
@@ -277,7 +277,7 @@
         keyboardActions = keyboardActions,
         maxLines = maxLines,
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         shape = RectangleShape,
         colors = colors
     )
@@ -297,7 +297,7 @@
     maxLines: Int = Int.MAX_VALUE,
     visualTransformation: VisualTransformation,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     decoratedPlaceholder: @Composable ((Modifier) -> Unit)?,
     decoratedLabel: @Composable (() -> Unit)?,
     leading: @Composable (() -> Unit)?,
@@ -339,7 +339,7 @@
         visualTransformation = visualTransformation,
         keyboardOptions = keyboardOptions,
         keyboardActions = keyboardActions,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         >
         singleLine = singleLine,
         maxLines = maxLines,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
index bdb73d6..d492b4a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
@@ -20,8 +20,8 @@
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.padding
@@ -60,10 +60,10 @@
  * @param modifier Modifier to be applied to the radio button
  * @param enabled Controls the enabled state of the [RadioButton]. When `false`, this button will
  * not be selectable and appears in the disabled ui state
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this RadioButton. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this RadioButton in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this RadioButton. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this RadioButton in different [Interaction]s.
  * @param colors [RadioButtonColors] that will be used to resolve the color used for this
  * RadioButton in different states. See [RadioButtonDefaults.colors].
  */
@@ -73,7 +73,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: RadioButtonColors = RadioButtonDefaults.colors()
 ) {
     val dotRadius by animateDpAsState(
@@ -88,7 +88,7 @@
                 >
                 enabled = enabled,
                 role = Role.RadioButton,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = rememberRipple(
                     bounded = false,
                     radius = RadioButtonRippleRadius
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index b4f757f..1d3a691 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -19,14 +19,17 @@
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
 import androidx.compose.foundation.focusable
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.foundation.gestures.draggable
 import androidx.compose.foundation.gestures.rememberDraggableState
 import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxWithConstraints
 import androidx.compose.foundation.layout.Spacer
@@ -42,6 +45,7 @@
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
@@ -63,6 +67,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.lerp
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
 import kotlin.math.abs
 
@@ -95,10 +100,10 @@
  * @param onValueChangeFinished lambda to be invoked when value change has ended. This callback
  * shouldn't be used to update the slider value (use [onValueChange] for that), but rather to
  * know when the user has completed selecting a new value by ending a drag or a click.
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Slider. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this Slider in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Slider. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Slider in different [Interaction]s.
  * @param colors [SliderColors] that will be used to determine the color of the Slider parts in
  * different state. See [SliderDefaults.colors] to customize.
  */
@@ -112,7 +117,7 @@
     /*@IntRange(from = 0)*/
     steps: Int = 0,
     onValueChangeFinished: (() -> Unit)? = null,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: SliderColors = SliderDefaults.colors()
 ) {
     val scope = rememberCoroutineScope()
@@ -150,10 +155,19 @@
                 detectTapGestures(
                      pos ->
                         position.snapTo(if (isRtl) maxPx - pos.x else pos.x)
-                        interactionState.addInteraction(Interaction.Pressed, pos)
+                        val interaction = PressInteraction.Press(pos)
+                        coroutineScope {
+                            launch {
+                                interactionSource.emit(interaction)
+                            }
+                        }
                         val success = tryAwaitRelease()
                         if (success) gestureEndAction(0f)
-                        interactionState.removeInteraction(Interaction.Pressed)
+                        coroutineScope {
+                            launch {
+                                interactionSource.emit(PressInteraction.Release(interaction))
+                            }
+                        }
                     }
                 )
             }
@@ -165,7 +179,7 @@
             orientation = Orientation.Horizontal,
             reverseDirection = isRtl,
             enabled = enabled,
-            interactionState = interactionState,
+            interactionSource = interactionSource,
              velocity -> gestureEndAction(velocity) },
             startDragImmediately = position.holder.isRunning,
             state = rememberDraggableState {
@@ -180,7 +194,7 @@
             position.tickFractions,
             colors,
             maxPx,
-            interactionState,
+            interactionSource,
             modifier = press.then(drag)
         )
     }
@@ -325,7 +339,7 @@
     tickFractions: List<Float>,
     colors: SliderColors,
     width: Float,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     modifier: Modifier
 ) {
     val widthDp = with(LocalDensity.current) {
@@ -352,9 +366,10 @@
             trackStrokeWidth
         )
         Box(center.padding(start = offset)) {
-            val elevation = if (
-                Interaction.Pressed in interactionState || Interaction.Dragged in interactionState
-            ) {
+            val isPressed by interactionSource.collectIsPressedAsState()
+            val isDragged by interactionSource.collectIsDraggedAsState()
+            val hasInteraction = isPressed || isDragged
+            val elevation = if (hasInteraction) {
                 ThumbPressedElevation
             } else {
                 ThumbDefaultElevation
@@ -364,9 +379,9 @@
                 color = colors.thumbColor(enabled).value,
                 elevation = if (enabled) elevation else 0.dp,
                 modifier = Modifier
-                    .focusable(interactionState = interactionState)
+                    .focusable(interactionSource = interactionSource)
                     .indication(
-                        interactionState = interactionState,
+                        interactionSource = interactionSource,
                         indication = rememberRipple(
                             bounded = false,
                             radius = ThumbRippleRadius
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
index c932987..8cbec9a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
@@ -19,8 +19,8 @@
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.SpringSpec
-import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.gestures.DraggableState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.draggable
 import androidx.compose.material.SwipeableDefaults.AnimationSpec
@@ -530,7 +530,8 @@
  * @param enabled Whether this [swipeable] is enabled and should react to the user's input.
  * @param reverseDirection Whether to reverse the direction of the swipe, so a top to bottom
  * swipe will behave like bottom to top, and a left to right swipe will behave like right to left.
- * @param interactionState Optional [InteractionState] that will passed on to [Modifier.draggable].
+ * @param interactionSource Optional [MutableInteractionSource] that will passed on to
+ * the internal [Modifier.draggable].
  * @param resistance Controls how much resistance will be applied when swiping past the bounds.
  * @param velocityThreshold The threshold (in dp per second) that the end velocity has to exceed
  * in order to animate to the next state, even if the positional [thresholds] have not been reached.
@@ -543,7 +544,7 @@
     orientation: Orientation,
     enabled: Boolean = true,
     reverseDirection: Boolean = false,
-    interactionState: InteractionState? = null,
+    interactionSource: MutableInteractionSource? = null,
     thresholds: (from: T, to: T) -> ThresholdConfig = { _, _ -> FixedThreshold(56.dp) },
     resistance: ResistanceConfig? = resistanceConfig(anchors.keys),
     velocityThreshold: Dp = VelocityThreshold
@@ -555,7 +556,7 @@
         properties["orientation"] = orientation
         properties["enabled"] = enabled
         properties["reverseDirection"] = reverseDirection
-        properties["interactionState"] = interactionState
+        properties["interactionSource"] = interactionSource
         properties["thresholds"] = thresholds
         properties["resistance"] = resistance
         properties["velocityThreshold"] = velocityThreshold
@@ -590,7 +591,7 @@
         orientation = orientation,
         enabled = enabled,
         reverseDirection = reverseDirection,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         startDragImmediately = state.isAnimationRunning,
          velocity -> launch { state.performFling(velocity) } },
         state = state.draggableState
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
index cbd704a..520e39e 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
@@ -18,10 +18,13 @@
 
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
+import androidx.compose.foundation.interaction.collectIsPressedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.fillMaxSize
@@ -64,10 +67,10 @@
  * therefore the change of checked state is requested.
  * @param modifier Modifier to be applied to the switch layout
  * @param enabled whether or not components is enabled and can be clicked to request state change
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Switch. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this Switch in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Switch. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Switch in different [Interaction]s.
  * @param colors [SwitchColors] that will be used to determine the color of the thumb and track
  * in different states. See [SwitchDefaults.colors].
  */
@@ -78,7 +81,7 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     colors: SwitchColors = SwitchDefaults.colors()
 ) {
     val minBound = 0f
@@ -92,7 +95,7 @@
                 >
                 enabled = enabled,
                 role = Role.Switch,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = null
             )
             .swipeable(
@@ -102,7 +105,7 @@
                 orientation = Orientation.Horizontal,
                 enabled = enabled,
                 reverseDirection = isRtl,
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 resistance = null
             )
             .wrapContentSize(Alignment.Center)
@@ -114,7 +117,7 @@
             enabled = enabled,
             colors = colors,
             thumbValue = swipeableState.offset,
-            interactionState = interactionState
+            interactionSource = interactionSource
         )
     }
 }
@@ -153,10 +156,11 @@
     enabled: Boolean,
     colors: SwitchColors,
     thumbValue: State<Float>,
-    interactionState: InteractionState
+    interactionSource: InteractionSource
 ) {
-    val hasInteraction =
-        Interaction.Pressed in interactionState || Interaction.Dragged in interactionState
+    val isPressed by interactionSource.collectIsPressedAsState()
+    val isDragged by interactionSource.collectIsDraggedAsState()
+    val hasInteraction = isPressed || isDragged
     val elevation = if (hasInteraction) {
         ThumbPressedElevation
     } else {
@@ -175,7 +179,7 @@
             .align(Alignment.CenterStart)
             .offset { IntOffset(thumbValue.value.roundToInt(), 0) }
             .indication(
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 indication = rememberRipple(bounded = false, radius = ThumbRippleRadius)
             )
             .requiredSize(ThumbDiameter),
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt
index abe0b41..0d107e4 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Tab.kt
@@ -20,8 +20,8 @@
 import androidx.compose.animation.core.LinearEasing
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -66,10 +66,10 @@
  * be clickable and will appear disabled to accessibility services.
  * @param text the text label displayed in this tab
  * @param icon the icon displayed in this tab
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Tab. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this Tab
- * in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Tab. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Tab in different [Interaction]s.
  * @param selectedContentColor the color for the content of this tab when selected, and the color
  * of the ripple.
  * @param unselectedContentColor the color for the content of this tab when not selected
@@ -82,7 +82,7 @@
     enabled: Boolean = true,
     text: @Composable (() -> Unit)? = null,
     icon: @Composable (() -> Unit)? = null,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     selectedContentColor: Color = LocalContentColor.current,
     unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)
 ) {
@@ -97,7 +97,7 @@
         onClick,
         modifier,
         enabled,
-        interactionState,
+        interactionSource,
         selectedContentColor,
         unselectedContentColor
     ) {
@@ -119,10 +119,10 @@
  * @param modifier optional [Modifier] for this tab
  * @param enabled controls the enabled state of this tab. When `false`, this tab will not
  * be clickable and will appear disabled to accessibility services.
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this Tab. You can create and pass in your own remembered [InteractionState] if
- * you want to read the [InteractionState] and customize the appearance / behavior of this Tab
- * in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this Tab. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Tab in different [Interaction]s.
  * @param selectedContentColor the color for the content of this tab when selected, and the color
  * of the ripple.
  * @param unselectedContentColor the color for the content of this tab when not selected
@@ -134,7 +134,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     selectedContentColor: Color = LocalContentColor.current,
     unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium),
     content: @Composable ColumnScope.() -> Unit
@@ -152,7 +152,7 @@
                     >
                     enabled = enabled,
                     role = Role.Tab,
-                    interactionState = interactionState,
+                    interactionSource = interactionSource,
                     indication = ripple
                 )
                 .fillMaxWidth(),
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
index 7adcdd5..a772166 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
@@ -16,8 +16,8 @@
 
 package androidx.compose.material
 
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.defaultMinSize
@@ -139,10 +139,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this TextField. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this TextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this TextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this TextField in different [Interaction]s.
  * @param shape the shape of the text field's container
  * @param colors [TextFieldColors] that will be used to resolve color of the text, content
  * (including label, placeholder, leading and trailing icons, indicator line) and background for
@@ -167,7 +167,7 @@
     singleLine: Boolean = false,
     maxLines: Int = Int.MAX_VALUE,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     shape: Shape =
         MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
     colors: TextFieldColors = TextFieldDefaults.textFieldColors()
@@ -198,7 +198,7 @@
         keyboardActions = keyboardActions,
         maxLines = maxLines,
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         shape = shape,
         colors = colors
     )
@@ -261,10 +261,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
- * @param interactionState the [InteractionState] representing the different [Interaction]s
- * present on this TextField. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this TextField in different [Interaction]s.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this TextField. You can create and pass in your own remembered
+ * [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this TextField in different [Interaction]s.
  * @param shape the shape of the text field's container
  * @param colors [TextFieldColors] that will be used to resolve color of the text, content
  * (including label, placeholder, leading and trailing icons, indicator line) and background for
@@ -289,7 +289,7 @@
     singleLine: Boolean = false,
     maxLines: Int = Int.MAX_VALUE,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     shape: Shape =
         MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
     colors: TextFieldColors = TextFieldDefaults.textFieldColors()
@@ -313,7 +313,7 @@
         keyboardActions = keyboardActions,
         maxLines = maxLines,
         >
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         shape = shape,
         colors = colors
     )
@@ -333,7 +333,7 @@
     maxLines: Int = Int.MAX_VALUE,
     visualTransformation: VisualTransformation,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     decoratedPlaceholder: @Composable ((Modifier) -> Unit)?,
     decoratedLabel: @Composable (() -> Unit)?,
     leading: @Composable (() -> Unit)?,
@@ -365,7 +365,7 @@
         visualTransformation = visualTransformation,
         keyboardOptions = keyboardOptions,
         keyboardActions = keyboardActions,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         >
         singleLine = singleLine,
         maxLines = maxLines,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt
index f5d36ec..3432747 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldDefaults.kt
@@ -18,15 +18,20 @@
 
 import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.InteractionSource
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import kotlinx.coroutines.flow.collect
 
 /**
  * Represents the colors of the input text, background and content (including label, placeholder,
@@ -67,14 +72,14 @@
      *
      * @param enabled whether the text field is enabled
      * @param error whether the text field's current value is in error
-     * @param interactionState the [InteractionState] of this text field. Helps to determine if
+     * @param interactionSource the [InteractionSource] of this text field. Helps to determine if
      * the text field is in focus or not
      */
     @Composable
     fun labelColor(
         enabled: Boolean,
         error: Boolean,
-        interactionState: InteractionState
+        interactionSource: InteractionSource
     ): State<Color>
 
     /**
@@ -100,14 +105,14 @@
      *
      * @param enabled whether the text field is enabled
      * @param isError whether the text field's current value is in error
-     * @param interactionState the [InteractionState] of this text field. Helps to determine if
+     * @param interactionSource the [InteractionSource] of this text field. Helps to determine if
      * the text field is in focus or not
      */
     @Composable
     fun indicatorColor(
         enabled: Boolean,
         isError: Boolean,
-        interactionState: InteractionState
+        interactionSource: InteractionSource
     ): State<Color>
 
     /**
@@ -320,15 +325,27 @@
     override fun indicatorColor(
         enabled: Boolean,
         isError: Boolean,
-        interactionState: InteractionState
+        interactionSource: InteractionSource
     ): State<Color> {
-        val interaction = interactionState.value.lastOrNull {
-            it is Interaction.Focused
+        val interactions = remember { mutableStateListOf<Interaction>() }
+        LaunchedEffect(interactionSource) {
+            interactionSource.interactions.collect { interaction ->
+                when (interaction) {
+                    is FocusInteraction.Focus -> {
+                        interactions.add(interaction)
+                    }
+                    is FocusInteraction.Unfocus -> {
+                        interactions.remove(interaction.focus)
+                    }
+                }
+            }
         }
+        val interaction = interactions.lastOrNull()
+
         val targetValue = when {
             !enabled -> disabledIndicatorColor
             isError -> errorIndicatorColor
-            interaction == Interaction.Focused -> focusedIndicatorColor
+            interaction is FocusInteraction.Focus -> focusedIndicatorColor
             else -> unfocusedIndicatorColor
         }
         return if (enabled) {
@@ -352,15 +369,27 @@
     override fun labelColor(
         enabled: Boolean,
         error: Boolean,
-        interactionState: InteractionState
+        interactionSource: InteractionSource
     ): State<Color> {
-        val interaction = interactionState.value.lastOrNull {
-            it is Interaction.Focused
+        val interactions = remember { mutableStateListOf<Interaction>() }
+        LaunchedEffect(interactionSource) {
+            interactionSource.interactions.collect { interaction ->
+                when (interaction) {
+                    is FocusInteraction.Focus -> {
+                        interactions.add(interaction)
+                    }
+                    is FocusInteraction.Unfocus -> {
+                        interactions.remove(interaction.focus)
+                    }
+                }
+            }
         }
+        val interaction = interactions.lastOrNull()
+
         val targetValue = when {
             !enabled -> disabledLabelColor
             error -> errorLabelColor
-            interaction == Interaction.Focused -> focusedLabelColor
+            interaction is FocusInteraction.Focus -> focusedLabelColor
             else -> unfocusedLabelColor
         }
         return if (enabled) {
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
index e6d8af7..5249570 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
@@ -22,9 +22,8 @@
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.core.updateTransition
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Interaction
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
@@ -62,7 +61,6 @@
  * Implementation of the [TextField] and [OutlinedTextField]
  */
 @Composable
-@OptIn(ExperimentalFoundationApi::class)
 internal fun TextFieldImpl(
     type: TextFieldType,
     enabled: Boolean,
@@ -82,7 +80,7 @@
     keyboardActions: KeyboardActions,
     maxLines: Int = Int.MAX_VALUE,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit,
-    interactionState: InteractionState,
+    interactionSource: MutableInteractionSource,
     shape: Shape,
     colors: TextFieldColors
 ) {
@@ -92,7 +90,7 @@
     }
     val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
 
-    val isFocused = interactionState.contains(Interaction.Focused)
+    val isFocused = interactionSource.collectIsFocusedAsState().value
     val inputState = when {
         isFocused -> InputPhase.Focused
         value.text.isEmpty() -> InputPhase.UnfocusedEmpty
@@ -112,7 +110,7 @@
                         labelProgress
                     )
                     Decoration(
-                        contentColor = colors.labelColor(enabled, isError, interactionState).value,
+                        contentColor = colors.labelColor(enabled, isError, interactionSource).value,
                         typography = labelAnimatedStyle,
                         content = label
                     )
@@ -147,7 +145,7 @@
                     maxLines = maxLines,
                     visualTransformation = visualTransformation,
                     >
-                    interactionState = interactionState,
+                    interactionSource = interactionSource,
                     decoratedPlaceholder = decoratedPlaceholder,
                     decoratedLabel = decoratedLabel,
                     leading = leading,
@@ -157,7 +155,7 @@
                     labelProgress = labelProgress,
                     indicatorWidth = indicatorWidth,
                     indicatorColor =
-                        colors.indicatorColor(enabled, isError, interactionState).value,
+                        colors.indicatorColor(enabled, isError, interactionSource).value,
                     backgroundColor = colors.backgroundColor(enabled).value,
                     cursorColor = colors.cursorColor(isError).value,
                     shape = shape
@@ -177,7 +175,7 @@
                     maxLines = maxLines,
                     visualTransformation = visualTransformation,
                     >
-                    interactionState = interactionState,
+                    interactionSource = interactionSource,
                     decoratedPlaceholder = decoratedPlaceholder,
                     decoratedLabel = decoratedLabel,
                     leading = leading,
@@ -187,7 +185,7 @@
                     labelProgress = labelProgress,
                     indicatorWidth = indicatorWidth,
                     indicatorColor =
-                        colors.indicatorColor(enabled, isError, interactionState).value,
+                        colors.indicatorColor(enabled, isError, interactionSource).value,
                     cursorColor = colors.cursorColor(isError).value
                 )
             }
diff --git a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
index a5ae05a..8142487 100644
--- a/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
+++ b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/DesktopMenu.desktop.kt
@@ -17,7 +17,7 @@
 package androidx.compose.material
 
 import androidx.compose.animation.core.MutableTransitionState
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.RowScope
@@ -110,10 +110,10 @@
  * @param enabled Controls the enabled state of the menu item - when `false`, the menu item
  * will not be clickable and [onClick] will not be invoked
  * @param contentPadding the padding applied to the content of this menu item
- * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * @param interactionSource the [MutableInteractionSource] representing the different [Interaction]s
  * present on this DropdownMenuItem. You can create and pass in your own remembered
- * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
- * behavior of this DropdownMenuItem in different [Interaction]s.
+ * [MutableInteractionSource] if you want to read the [MutableInteractionSource] and customize
+ * the appearance / behavior of this DropdownMenuItem in different [Interaction]s.
  */
 @Composable
 fun DropdownMenuItem(
@@ -121,7 +121,7 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding,
-    interactionState: InteractionState = remember { InteractionState() },
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
     content: @Composable RowScope.() -> Unit
 ) {
     DropdownMenuItemContent(
@@ -129,7 +129,7 @@
         modifier = modifier,
         enabled = enabled,
         contentPadding = contentPadding,
-        interactionState = interactionState,
+        interactionSource = interactionSource,
         content = content
     )
 }
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt
index 888edcc..fea7034 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/gestures/ScrollGestureFilterDemo.kt
@@ -16,11 +16,11 @@
 
 package androidx.compose.ui.demos.gestures
 
-import androidx.compose.foundation.Interaction.Dragged
-import androidx.compose.foundation.InteractionState
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.rememberScrollableState
 import androidx.compose.foundation.gestures.scrollable
+import androidx.compose.foundation.interaction.collectIsDraggedAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
@@ -68,8 +68,8 @@
     content: @Composable () -> Unit = {}
 ) {
 
-    val interactionState = remember { InteractionState() }
-    val color = if (interactionState.contains(Dragged)) activeColor else idleColor
+    val interactionSource = remember { MutableInteractionSource() }
+    val color = if (interactionSource.collectIsDraggedAsState().value) activeColor else idleColor
     val offsetPx = remember { mutableStateOf(0f) }
 
     val offsetDp = with(LocalDensity.current) {
@@ -85,7 +85,7 @@
             .fillMaxSize()
             .wrapContentSize(Alignment.Center)
             .scrollable(
-                interactionState = interactionState,
+                interactionSource = interactionSource,
                 orientation = orientation,
                 state = rememberScrollableState { scrollDistance ->
                     offsetPx.value += scrollDistance