Merge "Add sample of links styling to material text" into androidx-main
diff --git a/compose/material3/material3/api/1.3.0-beta01.txt b/compose/material3/material3/api/1.3.0-beta01.txt
index c4a1b23..f92b5a9 100644
--- a/compose/material3/material3/api/1.3.0-beta01.txt
+++ b/compose/material3/material3/api/1.3.0-beta01.txt
@@ -17,12 +17,15 @@
     field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
   }
 
-  public final class AndroidAlertDialog_androidKt {
+  public final class AlertDialogKt {
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
@@ -2009,6 +2012,8 @@
   }
 
   public final class TooltipKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipScope,kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
@@ -2030,11 +2035,6 @@
     property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
   }
 
-  public final class Tooltip_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
-  }
-
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
     ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
     method public androidx.compose.material3.TopAppBarColors copy(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index c4a1b23..f92b5a9 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -17,12 +17,15 @@
     field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
   }
 
-  public final class AndroidAlertDialog_androidKt {
+  public final class AlertDialogKt {
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
@@ -2009,6 +2012,8 @@
   }
 
   public final class TooltipKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipScope,kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
@@ -2030,11 +2035,6 @@
     property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
   }
 
-  public final class Tooltip_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
-  }
-
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
     ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
     method public androidx.compose.material3.TopAppBarColors copy(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
diff --git a/compose/material3/material3/api/restricted_1.3.0-beta01.txt b/compose/material3/material3/api/restricted_1.3.0-beta01.txt
index c4a1b23..f92b5a9 100644
--- a/compose/material3/material3/api/restricted_1.3.0-beta01.txt
+++ b/compose/material3/material3/api/restricted_1.3.0-beta01.txt
@@ -17,12 +17,15 @@
     field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
   }
 
-  public final class AndroidAlertDialog_androidKt {
+  public final class AlertDialogKt {
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
@@ -2009,6 +2012,8 @@
   }
 
   public final class TooltipKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipScope,kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
@@ -2030,11 +2035,6 @@
     property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
   }
 
-  public final class Tooltip_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
-  }
-
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
     ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
     method public androidx.compose.material3.TopAppBarColors copy(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index c4a1b23..f92b5a9 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -17,12 +17,15 @@
     field public static final androidx.compose.material3.AlertDialogDefaults INSTANCE;
   }
 
-  public final class AndroidAlertDialog_androidKt {
+  public final class AlertDialogKt {
     method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void BasicAlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.ui.window.DialogProperties properties, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
+  public final class AndroidAlertDialog_androidKt {
+    method @androidx.compose.runtime.Composable public static void AlertDialog(kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, kotlin.jvm.functions.Function0<kotlin.Unit> confirmButton, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? dismissButton, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? text, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional long iconContentColor, optional long titleContentColor, optional long textContentColor, optional float tonalElevation, optional androidx.compose.ui.window.DialogProperties properties);
+  }
+
   public final class AndroidMenu_androidKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, optional androidx.compose.ui.graphics.Shape shape, optional long containerColor, optional float tonalElevation, optional float shadowElevation, optional androidx.compose.foundation.BorderStroke? border, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
     method @Deprecated @androidx.compose.runtime.Composable public static void DropdownMenu(boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.Modifier modifier, optional long offset, optional androidx.compose.foundation.ScrollState scrollState, optional androidx.compose.ui.window.PopupProperties properties, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
@@ -2009,6 +2012,8 @@
   }
 
   public final class TooltipKt {
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TooltipBox(androidx.compose.ui.window.PopupPositionProvider positionProvider, kotlin.jvm.functions.Function1<? super androidx.compose.material3.TooltipScope,kotlin.Unit> tooltip, androidx.compose.material3.TooltipState state, optional androidx.compose.ui.Modifier modifier, optional boolean focusable, optional boolean enableUserInput, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public static androidx.compose.material3.TooltipState TooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
     method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.TooltipState rememberTooltipState(optional boolean initialIsVisible, optional boolean isPersistent, optional androidx.compose.foundation.MutatorMutex mutatorMutex);
@@ -2030,11 +2035,6 @@
     property public abstract androidx.compose.animation.core.MutableTransitionState<java.lang.Boolean> transition;
   }
 
-  public final class Tooltip_androidKt {
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void PlainTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional long contentColor, optional long containerColor, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void RichTooltip(androidx.compose.material3.TooltipScope, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? title, optional kotlin.jvm.functions.Function0<kotlin.Unit>? action, optional long caretSize, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.RichTooltipColors colors, optional float tonalElevation, optional float shadowElevation, kotlin.jvm.functions.Function0<kotlin.Unit> text);
-  }
-
   @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public final class TopAppBarColors {
     ctor public TopAppBarColors(long containerColor, long scrolledContainerColor, long navigationIconContentColor, long titleContentColor, long actionIconContentColor);
     method public androidx.compose.material3.TopAppBarColors copy(optional long containerColor, optional long scrolledContainerColor, optional long navigationIconContentColor, optional long titleContentColor, optional long actionIconContentColor);
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/AndroidAlertDialog.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/AndroidAlertDialog.android.kt
index 0aede79..060ab2b 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/AndroidAlertDialog.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/AndroidAlertDialog.android.kt
@@ -16,223 +16,46 @@
 
 package androidx.compose.material3
 
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.material3.internal.Strings
-import androidx.compose.material3.internal.getString
-import androidx.compose.material3.tokens.DialogTokens
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.semantics.paneTitle
-import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.Dialog
 import androidx.compose.ui.window.DialogProperties
 
-/**
- * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Material Design basic dialog</a>.
- *
- * Dialogs provide important prompts in a user flow. They can require an action, communicate
- * information, or help users accomplish a task.
- *
- * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
- *
- * The dialog will position its buttons, typically [TextButton]s, based on the available space.
- * By default it will try to place them horizontally next to each other and fallback to horizontal
- * placement if not enough space is available.
- *
- * Simple usage:
- * @sample androidx.compose.material3.samples.AlertDialogSample
- *
- * Usage with a "Hero" icon:
- * @sample androidx.compose.material3.samples.AlertDialogWithIconSample
- *
- * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
- * or pressing the back button. This is not called when the dismiss button is clicked.
- * @param confirmButton button which is meant to confirm a proposed action, thus resolving what
- * triggered the dialog. The dialog does not set up any events for this button so they need to be
- * set up by the caller.
- * @param modifier the [Modifier] to be applied to this dialog
- * @param dismissButton button which is meant to dismiss the dialog. The dialog does not set up any
- * events for this button so they need to be set up by the caller.
- * @param icon optional icon that will appear above the [title] or above the [text], in case a
- * title was not provided.
- * @param title title which should specify the purpose of the dialog. The title is not mandatory,
- * because there may be sufficient information inside the [text].
- * @param text text which presents the details regarding the dialog's purpose.
- * @param shape defines the shape of this dialog's container
- * @param containerColor the color used for the background of this dialog. Use [Color.Transparent]
- * to have no color.
- * @param iconContentColor the content color used for the icon.
- * @param titleContentColor the content color used for the title.
- * @param textContentColor the content color used for the text.
- * @param tonalElevation when [containerColor] is [ColorScheme.surface], a translucent primary color
- * overlay is applied on top of the container. A higher tonal elevation value will result in a
- * darker color in light theme and lighter color in dark theme. See also: [Surface].
- * @param properties typically platform specific properties to further configure the dialog.
- * @see BasicAlertDialog
- */
-@OptIn(ExperimentalMaterial3Api::class)
+// Keep expect/actual for maintain binary compatibility.
+// `@file:JvmName` doesn't work here because Android and Desktop were published with different names
+// Please note that binary compatibility for Desktop is tracked only in JetBrains fork
+
 @Composable
-fun AlertDialog(
+actual fun AlertDialog(
     onDismissRequest: () -> Unit,
     confirmButton: @Composable () -> Unit,
-    modifier: Modifier = Modifier,
-    dismissButton: @Composable (() -> Unit)? = null,
-    icon: @Composable (() -> Unit)? = null,
-    title: @Composable (() -> Unit)? = null,
-    text: @Composable (() -> Unit)? = null,
-    shape: Shape = AlertDialogDefaults.shape,
-    containerColor: Color = AlertDialogDefaults.containerColor,
-    iconContentColor: Color = AlertDialogDefaults.iconContentColor,
-    titleContentColor: Color = AlertDialogDefaults.titleContentColor,
-    textContentColor: Color = AlertDialogDefaults.textContentColor,
-    tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
-    properties: DialogProperties = DialogProperties()
-) = BasicAlertDialog(
+    modifier: Modifier,
+    dismissButton: @Composable (() -> Unit)?,
+    icon: @Composable (() -> Unit)?,
+    title: @Composable (() -> Unit)?,
+    text: @Composable (() -> Unit)?,
+    shape: Shape,
+    containerColor: Color,
+    iconContentColor: Color,
+    titleContentColor: Color,
+    textContentColor: Color,
+    tonalElevation: Dp,
+    properties: DialogProperties
+): Unit = AlertDialogImpl(
     onDismissRequest = onDismissRequest,
+    confirmButton = confirmButton,
     modifier = modifier,
+    dismissButton = dismissButton,
+    icon = icon,
+    title = title,
+    text = text,
+    shape = shape,
+    containerColor = containerColor,
+    iconContentColor = iconContentColor,
+    titleContentColor = titleContentColor,
+    textContentColor = textContentColor,
+    tonalElevation = tonalElevation,
     properties = properties
-) {
-    AlertDialogContent(
-        buttons = {
-            AlertDialogFlowRow(
-                mainAxisSpacing = ButtonsMainAxisSpacing,
-                crossAxisSpacing = ButtonsCrossAxisSpacing
-            ) {
-                dismissButton?.invoke()
-                confirmButton()
-            }
-        },
-        icon = icon,
-        title = title,
-        text = text,
-        shape = shape,
-        containerColor = containerColor,
-        tonalElevation = tonalElevation,
-        // Note that a button content color is provided here from the dialog's token, but in
-        // most cases, TextButtons should be used for dismiss and confirm buttons.
-        // TextButtons will not consume this provided content color value, and will used their
-        // own defined or default colors.
-        buttonContentColor = DialogTokens.ActionLabelTextColor.value,
-        iconContentColor = iconContentColor,
-        titleContentColor = titleContentColor,
-        textContentColor = textContentColor,
-    )
-}
-
-/**
- * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Basic alert dialog dialog</a>.
- *
- * Dialogs provide important prompts in a user flow. They can require an action, communicate
- * information, or help users accomplish a task.
- *
- * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
- *
- * This basic alert dialog expects an arbitrary content that is defined by the caller. Note that
- * your content will need to define its own styling.
- *
- * By default, the displayed dialog has the minimum height and width that the Material Design spec
- * defines. If required, these constraints can be overwritten by providing a `width` or `height`
- * [Modifier]s.
- *
- * Basic alert dialog usage with custom content:
- * @sample androidx.compose.material3.samples.BasicAlertDialogSample
- *
- * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
- * or pressing the back button. This is not called when the dismiss button is clicked.
- * @param modifier the [Modifier] to be applied to this dialog's content.
- * @param properties typically platform specific properties to further configure the dialog.
- * @param content the content of the dialog
- */
-@ExperimentalMaterial3Api
-@Composable
-fun BasicAlertDialog(
-    onDismissRequest: () -> Unit,
-    modifier: Modifier = Modifier,
-    properties: DialogProperties = DialogProperties(),
-    content: @Composable () -> Unit
-) {
-    Dialog(
-        onDismissRequest = onDismissRequest,
-        properties = properties,
-    ) {
-        val dialogPaneDescription = getString(Strings.Dialog)
-        Box(
-            modifier = modifier
-                .sizeIn(minWidth = DialogMinWidth, maxWidth = DialogMaxWidth)
-                .then(Modifier.semantics { paneTitle = dialogPaneDescription }),
-            propagateMinConstraints = true
-        ) {
-            content()
-        }
-    }
-}
-
-/**
- * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Basic alert dialog dialog</a>.
- *
- * Dialogs provide important prompts in a user flow. They can require an action, communicate
- * information, or help users accomplish a task.
- *
- * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
- *
- * This basic alert dialog expects an arbitrary content that is defined by the caller. Note that
- * your content will need to define its own styling.
- *
- * By default, the displayed dialog has the minimum height and width that the Material Design spec
- * defines. If required, these constraints can be overwritten by providing a `width` or `height`
- * [Modifier]s.
- *
- * Basic alert dialog usage with custom content:
- * @sample androidx.compose.material3.samples.BasicAlertDialogSample
- *
- * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
- * or pressing the back button. This is not called when the dismiss button is clicked.
- * @param modifier the [Modifier] to be applied to this dialog's content.
- * @param properties typically platform specific properties to further configure the dialog.
- * @param content the content of the dialog
- */
-@Deprecated(
-    "Use BasicAlertDialog instead",
-    replaceWith = ReplaceWith(
-        "BasicAlertDialog(onDismissRequest, modifier, properties, content)"
-    )
 )
-@ExperimentalMaterial3Api
-@Composable
-fun AlertDialog(
-    onDismissRequest: () -> Unit,
-    modifier: Modifier = Modifier,
-    properties: DialogProperties = DialogProperties(),
-    content: @Composable () -> Unit
-) = BasicAlertDialog(onDismissRequest, modifier, properties, content)
-
-/**
- * Contains default values used for [AlertDialog] and [BasicAlertDialog].
- */
-object AlertDialogDefaults {
-    /** The default shape for alert dialogs */
-    val shape: Shape @Composable get() = DialogTokens.ContainerShape.value
-
-    /** The default container color for alert dialogs */
-    val containerColor: Color @Composable get() = DialogTokens.ContainerColor.value
-
-    /** The default icon color for alert dialogs */
-    val iconContentColor: Color @Composable get() = DialogTokens.IconColor.value
-
-    /** The default title color for alert dialogs */
-    val titleContentColor: Color @Composable get() = DialogTokens.HeadlineColor.value
-
-    /** The default text color for alert dialogs */
-    val textContentColor: Color @Composable get() = DialogTokens.SupportingTextColor.value
-
-    /** The default tonal elevation for alert dialogs */
-    val TonalElevation: Dp = 0.dp
-}
-
-private val ButtonsMainAxisSpacing = 8.dp
-private val ButtonsCrossAxisSpacing = 12.dp
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
index 8777756..b42e087 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/Tooltip.android.kt
@@ -16,320 +16,12 @@
 
 package androidx.compose.material3
 
-import android.content.res.Configuration
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.paddingFromBaseline
-import androidx.compose.foundation.layout.requiredHeightIn
-import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.material3.tokens.PlainTooltipTokens
-import androidx.compose.material3.tokens.RichTooltipTokens
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.CacheDrawScope
-import androidx.compose.ui.draw.DrawResult
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Path
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.layout.LayoutCoordinates
-import androidx.compose.ui.layout.boundsInWindow
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.isSpecified
 
-/**
- * Plain tooltip that provides a descriptive message.
- *
- * Usually used with [TooltipBox].
- *
- * @param modifier the [Modifier] to be applied to the tooltip.
- * @param caretSize [DpSize] for the caret of the tooltip, if a default
- * caret is desired with a specific dimension. Please see [TooltipDefaults.caretSize] to
- * see the default dimensions. Pass in Dp.Unspecified for this parameter if no caret is desired.
- * @param shape the [Shape] that should be applied to the tooltip container.
- * @param contentColor [Color] that will be applied to the tooltip's content.
- * @param containerColor [Color] that will be applied to the tooltip's container.
- * @param tonalElevation the tonal elevation of the tooltip.
- * @param shadowElevation the shadow elevation of the tooltip.
- * @param content the composable that will be used to populate the tooltip's content.
- */
 @Composable
-@ExperimentalMaterial3Api
-actual fun TooltipScope.PlainTooltip(
-    modifier: Modifier,
-    caretSize: DpSize,
-    shape: Shape,
-    contentColor: Color,
-    containerColor: Color,
-    tonalElevation: Dp,
-    shadowElevation: Dp,
-    content: @Composable () -> Unit
-) {
-    val drawCaretModifier =
-        if (caretSize.isSpecified) {
-            val density = LocalDensity.current
-            val configuration = LocalConfiguration.current
-            Modifier.drawCaret { anchorLayoutCoordinates ->
-                drawCaretWithPath(
-                    CaretType.Plain,
-                    density,
-                    configuration,
-                    containerColor,
-                    caretSize,
-                    anchorLayoutCoordinates
-                )
-            }.then(modifier)
-        } else modifier
-    Surface(
-        modifier = drawCaretModifier,
-        shape = shape,
-        color = containerColor,
-        tonalElevation = tonalElevation,
-        shadowElevation = shadowElevation
-    ) {
-        Box(modifier = Modifier
-            .sizeIn(
-                minWidth = TooltipMinWidth,
-                maxWidth = PlainTooltipMaxWidth,
-                minHeight = TooltipMinHeight
-            )
-            .padding(PlainTooltipContentPadding)
-        ) {
-            val textStyle =
-                PlainTooltipTokens.SupportingTextFont.value
-
-            CompositionLocalProvider(
-                LocalContentColor provides contentColor,
-                LocalTextStyle provides textStyle,
-                content = content
-            )
-        }
-    }
-}
-
-/**
- * Rich text tooltip that allows the user to pass in a title, text, and action.
- * Tooltips are used to provide a descriptive message.
- *
- * Usually used with [TooltipBox]
- *
- * @param modifier the [Modifier] to be applied to the tooltip.
- * @param title An optional title for the tooltip.
- * @param action An optional action for the tooltip.
- * @param caretSize [DpSize] for the caret of the tooltip, if a default
- * caret is desired with a specific dimension. Please see [TooltipDefaults.caretSize] to
- * see the default dimensions. Pass in Dp.Unspecified for this parameter if no caret is desired.
- * @param shape the [Shape] that should be applied to the tooltip container.
- * @param colors [RichTooltipColors] that will be applied to the tooltip's container and content.
- * @param tonalElevation the tonal elevation of the tooltip.
- * @param shadowElevation the shadow elevation of the tooltip.
- * @param text the composable that will be used to populate the rich tooltip's text.
- */
-@Composable
-@ExperimentalMaterial3Api
-actual fun TooltipScope.RichTooltip(
-    modifier: Modifier,
-    title: (@Composable () -> Unit)?,
-    action: (@Composable () -> Unit)?,
-    caretSize: DpSize,
-    shape: Shape,
-    colors: RichTooltipColors,
-    tonalElevation: Dp,
-    shadowElevation: Dp,
-    text: @Composable () -> Unit
-) {
-    val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
-    val elevatedColor =
-        MaterialTheme.colorScheme.applyTonalElevation(
-            colors.containerColor,
-            absoluteElevation
-        )
-    val drawCaretModifier =
-        if (caretSize.isSpecified) {
-            val density = LocalDensity.current
-            val configuration = LocalConfiguration.current
-            Modifier.drawCaret { anchorLayoutCoordinates ->
-                drawCaretWithPath(
-                    CaretType.Rich,
-                    density,
-                    configuration,
-                    elevatedColor,
-                    caretSize,
-                    anchorLayoutCoordinates
-                )
-            }.then(modifier)
-        } else modifier
-    Surface(
-        modifier = drawCaretModifier
-            .sizeIn(
-                minWidth = TooltipMinWidth,
-                maxWidth = RichTooltipMaxWidth,
-                minHeight = TooltipMinHeight
-            ),
-        shape = shape,
-        color = colors.containerColor,
-        tonalElevation = tonalElevation,
-        shadowElevation = shadowElevation
-    ) {
-        val actionLabelTextStyle = RichTooltipTokens.ActionLabelTextFont.value
-        val subheadTextStyle = RichTooltipTokens.SubheadFont.value
-        val supportingTextStyle = RichTooltipTokens.SupportingTextFont.value
-
-        Column(
-            modifier = Modifier.padding(horizontal = RichTooltipHorizontalPadding)
-        ) {
-            title?.let {
-                Box(
-                    modifier = Modifier.paddingFromBaseline(top = HeightToSubheadFirstLine)
-                ) {
-                    CompositionLocalProvider(
-                        LocalContentColor provides colors.titleContentColor,
-                        LocalTextStyle provides subheadTextStyle,
-                        content = it
-                    )
-                }
-            }
-            Box(
-                modifier = Modifier.textVerticalPadding(
-                    title != null,
-                    action != null
-                )
-            ) {
-                CompositionLocalProvider(
-                    LocalContentColor provides colors.contentColor,
-                    LocalTextStyle provides supportingTextStyle,
-                    content = text
-                )
-            }
-            action?.let {
-                Box(
-                    modifier = Modifier
-                        .requiredHeightIn(min = ActionLabelMinHeight)
-                        .padding(bottom = ActionLabelBottomPadding)
-                ) {
-                    CompositionLocalProvider(
-                        LocalContentColor provides colors.actionContentColor,
-                        LocalTextStyle provides actionLabelTextStyle,
-                        content = it
-                    )
-                }
-            }
-        }
-    }
-}
-
-@ExperimentalMaterial3Api
-private fun CacheDrawScope.drawCaretWithPath(
-    caretType: CaretType,
-    density: Density,
-    configuration: Configuration,
-    containerColor: Color,
-    caretSize: DpSize,
-    anchorLayoutCoordinates: LayoutCoordinates?
-): DrawResult {
-    val path = Path()
-
-    if (anchorLayoutCoordinates != null) {
-        val caretHeightPx: Int
-        val caretWidthPx: Int
-        val screenWidthPx: Int
-        val tooltipAnchorSpacing: Int
-        with(density) {
-            caretHeightPx = caretSize.height.roundToPx()
-            caretWidthPx = caretSize.width.roundToPx()
-            screenWidthPx = configuration.screenWidthDp.dp.roundToPx()
-            tooltipAnchorSpacing = SpacingBetweenTooltipAndAnchor.roundToPx()
-        }
-        val anchorBounds = anchorLayoutCoordinates.boundsInWindow()
-        val anchorLeft = anchorBounds.left
-        val anchorRight = anchorBounds.right
-        val anchorTop = anchorBounds.top
-        val anchorMid = (anchorRight + anchorLeft) / 2
-        val anchorWidth = anchorRight - anchorLeft
-        val tooltipWidth = this.size.width
-        val tooltipHeight = this.size.height
-        val isCaretTop = anchorTop - tooltipHeight - tooltipAnchorSpacing < 0
-        val caretY = if (isCaretTop) { 0f } else { tooltipHeight }
-
-        val position: Offset
-        if (caretType == CaretType.Plain) {
-            position =
-                if (anchorMid + tooltipWidth / 2 > screenWidthPx) {
-                    // Caret needs to be near the right
-                    val anchorMidFromRightScreenEdge =
-                        screenWidthPx - anchorMid
-                    val caretX = tooltipWidth - anchorMidFromRightScreenEdge
-                    Offset(caretX, caretY)
-                } else {
-                    // Caret needs to be near the left
-                    val tooltipLeft =
-                        anchorLeft - (this.size.width / 2 - anchorWidth / 2)
-                    val caretX = anchorMid - maxOf(tooltipLeft, 0f)
-                    Offset(caretX, caretY)
-                }
-        } else {
-            // Default the caret to the left
-            var preferredPosition = Offset(anchorMid - anchorLeft, caretY)
-            if (anchorLeft + tooltipWidth > screenWidthPx) {
-                // Need to move the caret to the right
-                preferredPosition = Offset(anchorMid - (anchorRight - tooltipWidth), caretY)
-                if (anchorRight - tooltipWidth < 0) {
-                    // Need to center the caret
-                    // Caret might need to be offset depending on where
-                    // the tooltip is placed relative to the anchor
-                    if (anchorLeft - tooltipWidth / 2 + anchorWidth / 2 <= 0) {
-                        preferredPosition = Offset(anchorMid, caretY)
-                    } else if (anchorRight + tooltipWidth / 2 - anchorWidth / 2 >= screenWidthPx) {
-                        val anchorMidFromRightScreenEdge =
-                            screenWidthPx - anchorMid
-                        val caretX = tooltipWidth - anchorMidFromRightScreenEdge
-                        preferredPosition = Offset(caretX, caretY)
-                    } else {
-                        preferredPosition = Offset(tooltipWidth / 2, caretY)
-                    }
-                }
-            }
-            position = preferredPosition
-        }
-
-        if (isCaretTop) {
-            path.apply {
-                moveTo(x = position.x, y = position.y)
-                lineTo(x = position.x + caretWidthPx / 2, y = position.y)
-                lineTo(x = position.x, y = position.y - caretHeightPx)
-                lineTo(x = position.x - caretWidthPx / 2, y = position.y)
-                close()
-            }
-        } else {
-            path.apply {
-                moveTo(x = position.x, y = position.y)
-                lineTo(x = position.x + caretWidthPx / 2, y = position.y)
-                lineTo(x = position.x, y = position.y + caretHeightPx.toFloat())
-                lineTo(x = position.x - caretWidthPx / 2, y = position.y)
-                close()
-            }
-        }
-    }
-
-    return onDrawWithContent {
-        if (anchorLayoutCoordinates != null) {
-            drawContent()
-            drawPath(
-                path = path,
-                color = containerColor
-            )
-        }
-    }
-}
-
-@ExperimentalMaterial3Api
-private enum class CaretType {
-    Plain, Rich
+internal actual fun windowContainerWidthInPx(): Int = with(LocalDensity.current) {
+    LocalConfiguration.current.screenWidthDp.dp.roundToPx()
 }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AlertDialog.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AlertDialog.kt
index cf167cd..ee43c24 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AlertDialog.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AlertDialog.kt
@@ -21,7 +21,10 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.sizeIn
 import androidx.compose.material3.internal.ProvideContentColorTextStyle
+import androidx.compose.material3.internal.Strings
+import androidx.compose.material3.internal.getString
 import androidx.compose.material3.tokens.DialogTokens
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -31,12 +34,236 @@
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.semantics.paneTitle
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.util.fastForEachIndexed
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.DialogProperties
 import kotlin.math.max
 
+/**
+ * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Material Design basic dialog</a>.
+ *
+ * Dialogs provide important prompts in a user flow. They can require an action, communicate
+ * information, or help users accomplish a task.
+ *
+ * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
+ *
+ * The dialog will position its buttons, typically [TextButton]s, based on the available space.
+ * By default it will try to place them horizontally next to each other and fallback to horizontal
+ * placement if not enough space is available.
+ *
+ * Simple usage:
+ * @sample androidx.compose.material3.samples.AlertDialogSample
+ *
+ * Usage with a "Hero" icon:
+ * @sample androidx.compose.material3.samples.AlertDialogWithIconSample
+ *
+ * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
+ * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param confirmButton button which is meant to confirm a proposed action, thus resolving what
+ * triggered the dialog. The dialog does not set up any events for this button so they need to be
+ * set up by the caller.
+ * @param modifier the [Modifier] to be applied to this dialog
+ * @param dismissButton button which is meant to dismiss the dialog. The dialog does not set up any
+ * events for this button so they need to be set up by the caller.
+ * @param icon optional icon that will appear above the [title] or above the [text], in case a
+ * title was not provided.
+ * @param title title which should specify the purpose of the dialog. The title is not mandatory,
+ * because there may be sufficient information inside the [text].
+ * @param text text which presents the details regarding the dialog's purpose.
+ * @param shape defines the shape of this dialog's container
+ * @param containerColor the color used for the background of this dialog. Use [Color.Transparent]
+ * to have no color.
+ * @param iconContentColor the content color used for the icon.
+ * @param titleContentColor the content color used for the title.
+ * @param textContentColor the content color used for the text.
+ * @param tonalElevation when [containerColor] is [ColorScheme.surface], a translucent primary color
+ * overlay is applied on top of the container. A higher tonal elevation value will result in a
+ * darker color in light theme and lighter color in dark theme. See also: [Surface].
+ * @param properties typically platform specific properties to further configure the dialog.
+ * @see BasicAlertDialog
+ */
+@Composable
+expect fun AlertDialog(
+    onDismissRequest: () -> Unit,
+    confirmButton: @Composable () -> Unit,
+    modifier: Modifier = Modifier,
+    dismissButton: @Composable (() -> Unit)? = null,
+    icon: @Composable (() -> Unit)? = null,
+    title: @Composable (() -> Unit)? = null,
+    text: @Composable (() -> Unit)? = null,
+    shape: Shape = AlertDialogDefaults.shape,
+    containerColor: Color = AlertDialogDefaults.containerColor,
+    iconContentColor: Color = AlertDialogDefaults.iconContentColor,
+    titleContentColor: Color = AlertDialogDefaults.titleContentColor,
+    textContentColor: Color = AlertDialogDefaults.textContentColor,
+    tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
+    properties: DialogProperties = DialogProperties()
+)
+
+/**
+ * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Basic alert dialog dialog</a>.
+ *
+ * Dialogs provide important prompts in a user flow. They can require an action, communicate
+ * information, or help users accomplish a task.
+ *
+ * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
+ *
+ * This basic alert dialog expects an arbitrary content that is defined by the caller. Note that
+ * your content will need to define its own styling.
+ *
+ * By default, the displayed dialog has the minimum height and width that the Material Design spec
+ * defines. If required, these constraints can be overwritten by providing a `width` or `height`
+ * [Modifier]s.
+ *
+ * Basic alert dialog usage with custom content:
+ * @sample androidx.compose.material3.samples.BasicAlertDialogSample
+ *
+ * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
+ * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param modifier the [Modifier] to be applied to this dialog's content.
+ * @param properties typically platform specific properties to further configure the dialog.
+ * @param content the content of the dialog
+ */
+@ExperimentalMaterial3Api
+@Composable
+fun BasicAlertDialog(
+    onDismissRequest: () -> Unit,
+    modifier: Modifier = Modifier,
+    properties: DialogProperties = DialogProperties(),
+    content: @Composable () -> Unit
+) {
+    Dialog(
+        onDismissRequest = onDismissRequest,
+        properties = properties,
+    ) {
+        val dialogPaneDescription = getString(Strings.Dialog)
+        Box(
+            modifier = modifier
+                .sizeIn(minWidth = DialogMinWidth, maxWidth = DialogMaxWidth)
+                .then(Modifier.semantics { paneTitle = dialogPaneDescription }),
+            propagateMinConstraints = true
+        ) {
+            content()
+        }
+    }
+}
+
+/**
+ * <a href="https://m3.material.io/components/dialogs/overview" class="external" target="_blank">Basic alert dialog dialog</a>.
+ *
+ * Dialogs provide important prompts in a user flow. They can require an action, communicate
+ * information, or help users accomplish a task.
+ *
+ * ![Basic dialog image](https://developer.android.com/images/reference/androidx/compose/material3/basic-dialog.png)
+ *
+ * This basic alert dialog expects an arbitrary content that is defined by the caller. Note that
+ * your content will need to define its own styling.
+ *
+ * By default, the displayed dialog has the minimum height and width that the Material Design spec
+ * defines. If required, these constraints can be overwritten by providing a `width` or `height`
+ * [Modifier]s.
+ *
+ * Basic alert dialog usage with custom content:
+ * @sample androidx.compose.material3.samples.BasicAlertDialogSample
+ *
+ * @param onDismissRequest called when the user tries to dismiss the Dialog by clicking outside
+ * or pressing the back button. This is not called when the dismiss button is clicked.
+ * @param modifier the [Modifier] to be applied to this dialog's content.
+ * @param properties typically platform specific properties to further configure the dialog.
+ * @param content the content of the dialog
+ */
+@Deprecated(
+    "Use BasicAlertDialog instead",
+    replaceWith = ReplaceWith(
+        "BasicAlertDialog(onDismissRequest, modifier, properties, content)"
+    )
+)
+@ExperimentalMaterial3Api
+@Composable
+fun AlertDialog(
+    onDismissRequest: () -> Unit,
+    modifier: Modifier = Modifier,
+    properties: DialogProperties = DialogProperties(),
+    content: @Composable () -> Unit
+) = BasicAlertDialog(onDismissRequest, modifier, properties, content)
+
+/**
+ * Contains default values used for [AlertDialog] and [BasicAlertDialog].
+ */
+object AlertDialogDefaults {
+    /** The default shape for alert dialogs */
+    val shape: Shape @Composable get() = DialogTokens.ContainerShape.value
+
+    /** The default container color for alert dialogs */
+    val containerColor: Color @Composable get() = DialogTokens.ContainerColor.value
+
+    /** The default icon color for alert dialogs */
+    val iconContentColor: Color @Composable get() = DialogTokens.IconColor.value
+
+    /** The default title color for alert dialogs */
+    val titleContentColor: Color @Composable get() = DialogTokens.HeadlineColor.value
+
+    /** The default text color for alert dialogs */
+    val textContentColor: Color @Composable get() = DialogTokens.SupportingTextColor.value
+
+    /** The default tonal elevation for alert dialogs */
+    val TonalElevation: Dp = 0.dp
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun AlertDialogImpl(
+    onDismissRequest: () -> Unit,
+    confirmButton: @Composable () -> Unit,
+    modifier: Modifier,
+    dismissButton: @Composable (() -> Unit)?,
+    icon: @Composable (() -> Unit)?,
+    title: @Composable (() -> Unit)?,
+    text: @Composable (() -> Unit)?,
+    shape: Shape,
+    containerColor: Color,
+    iconContentColor: Color,
+    titleContentColor: Color,
+    textContentColor: Color,
+    tonalElevation: Dp,
+    properties: DialogProperties
+): Unit = BasicAlertDialog(
+    onDismissRequest = onDismissRequest,
+    modifier = modifier,
+    properties = properties
+) {
+    AlertDialogContent(
+        buttons = {
+            AlertDialogFlowRow(
+                mainAxisSpacing = ButtonsMainAxisSpacing,
+                crossAxisSpacing = ButtonsCrossAxisSpacing
+            ) {
+                dismissButton?.invoke()
+                confirmButton()
+            }
+        },
+        icon = icon,
+        title = title,
+        text = text,
+        shape = shape,
+        containerColor = containerColor,
+        tonalElevation = tonalElevation,
+        // Note that a button content color is provided here from the dialog's token, but in
+        // most cases, TextButtons should be used for dismiss and confirm buttons.
+        // TextButtons will not consume this provided content color value, and will used their
+        // own defined or default colors.
+        buttonContentColor = DialogTokens.ActionLabelTextColor.value,
+        iconContentColor = iconContentColor,
+        titleContentColor = titleContentColor,
+        textContentColor = textContentColor,
+    )
+}
+
 @Composable
 internal fun AlertDialogContent(
     buttons: @Composable () -> Unit,
@@ -217,6 +444,9 @@
 internal val DialogMinWidth = 280.dp
 internal val DialogMaxWidth = 560.dp
 
+private val ButtonsMainAxisSpacing = 8.dp
+private val ButtonsCrossAxisSpacing = 12.dp
+
 // Paddings for each of the dialog's parts.
 private val DialogPadding = PaddingValues(all = 24.dp)
 private val IconPadding = PaddingValues(bottom = 16.dp)
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
index 366618d..18f443c 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Tooltip.kt
@@ -26,15 +26,19 @@
 import androidx.compose.foundation.MutatePriority
 import androidx.compose.foundation.MutatorMutex
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.paddingFromBaseline
+import androidx.compose.foundation.layout.requiredHeightIn
+import androidx.compose.foundation.layout.sizeIn
 import androidx.compose.material3.internal.BasicTooltipBox
 import androidx.compose.material3.internal.BasicTooltipDefaults
 import androidx.compose.material3.tokens.ElevationTokens
 import androidx.compose.material3.tokens.PlainTooltipTokens
 import androidx.compose.material3.tokens.RichTooltipTokens
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.Stable
@@ -46,14 +50,18 @@
 import androidx.compose.ui.draw.CacheDrawScope
 import androidx.compose.ui.draw.DrawResult
 import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.graphics.takeOrElse
 import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.boundsInWindow
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.debugInspectorInfo
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.IntOffset
@@ -61,6 +69,7 @@
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.isSpecified
 import androidx.compose.ui.window.PopupPositionProvider
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -199,7 +208,7 @@
  */
 @Composable
 @ExperimentalMaterial3Api
-expect fun TooltipScope.PlainTooltip(
+fun TooltipScope.PlainTooltip(
     modifier: Modifier = Modifier,
     caretSize: DpSize = DpSize.Unspecified,
     shape: Shape = TooltipDefaults.plainTooltipContainerShape,
@@ -208,7 +217,48 @@
     tonalElevation: Dp = 0.dp,
     shadowElevation: Dp = 0.dp,
     content: @Composable () -> Unit
-)
+) {
+    val drawCaretModifier =
+        if (caretSize.isSpecified) {
+            val density = LocalDensity.current
+            val windowContainerWidthInPx = windowContainerWidthInPx()
+            Modifier.drawCaret { anchorLayoutCoordinates ->
+                drawCaretWithPath(
+                    CaretType.Plain,
+                    density,
+                    windowContainerWidthInPx,
+                    containerColor,
+                    caretSize,
+                    anchorLayoutCoordinates
+                )
+            }.then(modifier)
+        } else modifier
+    Surface(
+        modifier = drawCaretModifier,
+        shape = shape,
+        color = containerColor,
+        tonalElevation = tonalElevation,
+        shadowElevation = shadowElevation
+    ) {
+        Box(modifier = Modifier
+            .sizeIn(
+                minWidth = TooltipMinWidth,
+                maxWidth = PlainTooltipMaxWidth,
+                minHeight = TooltipMinHeight
+            )
+            .padding(PlainTooltipContentPadding)
+        ) {
+            val textStyle =
+                PlainTooltipTokens.SupportingTextFont.value
+
+            CompositionLocalProvider(
+                LocalContentColor provides contentColor,
+                LocalTextStyle provides textStyle,
+                content = content
+            )
+        }
+    }
+}
 
 /**
  * Rich text tooltip that allows the user to pass in a title, text, and action.
@@ -230,7 +280,7 @@
  */
 @Composable
 @ExperimentalMaterial3Api
-expect fun TooltipScope.RichTooltip(
+fun TooltipScope.RichTooltip(
     modifier: Modifier = Modifier,
     title: (@Composable () -> Unit)? = null,
     action: (@Composable () -> Unit)? = null,
@@ -240,7 +290,86 @@
     tonalElevation: Dp = ElevationTokens.Level0,
     shadowElevation: Dp = RichTooltipTokens.ContainerElevation,
     text: @Composable () -> Unit
-)
+) {
+    val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
+    val elevatedColor =
+        MaterialTheme.colorScheme.applyTonalElevation(
+            colors.containerColor,
+            absoluteElevation
+        )
+    val drawCaretModifier =
+        if (caretSize.isSpecified) {
+            val density = LocalDensity.current
+            val windowContainerWidthInPx = windowContainerWidthInPx()
+            Modifier.drawCaret { anchorLayoutCoordinates ->
+                drawCaretWithPath(
+                    CaretType.Rich,
+                    density,
+                    windowContainerWidthInPx,
+                    elevatedColor,
+                    caretSize,
+                    anchorLayoutCoordinates
+                )
+            }.then(modifier)
+        } else modifier
+    Surface(
+        modifier = drawCaretModifier
+            .sizeIn(
+                minWidth = TooltipMinWidth,
+                maxWidth = RichTooltipMaxWidth,
+                minHeight = TooltipMinHeight
+            ),
+        shape = shape,
+        color = colors.containerColor,
+        tonalElevation = tonalElevation,
+        shadowElevation = shadowElevation
+    ) {
+        val actionLabelTextStyle = RichTooltipTokens.ActionLabelTextFont.value
+        val subheadTextStyle = RichTooltipTokens.SubheadFont.value
+        val supportingTextStyle = RichTooltipTokens.SupportingTextFont.value
+
+        Column(
+            modifier = Modifier.padding(horizontal = RichTooltipHorizontalPadding)
+        ) {
+            title?.let {
+                Box(
+                    modifier = Modifier.paddingFromBaseline(top = HeightToSubheadFirstLine)
+                ) {
+                    CompositionLocalProvider(
+                        LocalContentColor provides colors.titleContentColor,
+                        LocalTextStyle provides subheadTextStyle,
+                        content = it
+                    )
+                }
+            }
+            Box(
+                modifier = Modifier.textVerticalPadding(
+                    title != null,
+                    action != null
+                )
+            ) {
+                CompositionLocalProvider(
+                    LocalContentColor provides colors.contentColor,
+                    LocalTextStyle provides supportingTextStyle,
+                    content = text
+                )
+            }
+            action?.let {
+                Box(
+                    modifier = Modifier
+                        .requiredHeightIn(min = ActionLabelMinHeight)
+                        .padding(bottom = ActionLabelBottomPadding)
+                ) {
+                    CompositionLocalProvider(
+                        LocalContentColor provides colors.actionContentColor,
+                        LocalTextStyle provides actionLabelTextStyle,
+                        content = it
+                    )
+                }
+            }
+        }
+    }
+}
 
 /**
  * Tooltip defaults that contain default values for both [PlainTooltip] and [RichTooltip]
@@ -683,6 +812,118 @@
     )
 }
 
+@ExperimentalMaterial3Api
+private fun CacheDrawScope.drawCaretWithPath(
+    caretType: CaretType,
+    density: Density,
+    windowContainerWidthInPx: Int,
+    containerColor: Color,
+    caretSize: DpSize,
+    anchorLayoutCoordinates: LayoutCoordinates?
+): DrawResult {
+    val path = Path()
+
+    if (anchorLayoutCoordinates != null) {
+        val caretHeightPx: Int
+        val caretWidthPx: Int
+        val tooltipAnchorSpacing: Int
+        with(density) {
+            caretHeightPx = caretSize.height.roundToPx()
+            caretWidthPx = caretSize.width.roundToPx()
+            tooltipAnchorSpacing = SpacingBetweenTooltipAndAnchor.roundToPx()
+        }
+        val anchorBounds = anchorLayoutCoordinates.boundsInWindow()
+        val anchorLeft = anchorBounds.left
+        val anchorRight = anchorBounds.right
+        val anchorTop = anchorBounds.top
+        val anchorMid = (anchorRight + anchorLeft) / 2
+        val anchorWidth = anchorRight - anchorLeft
+        val tooltipWidth = this.size.width
+        val tooltipHeight = this.size.height
+        val isCaretTop = anchorTop - tooltipHeight - tooltipAnchorSpacing < 0
+        val caretY = if (isCaretTop) { 0f } else { tooltipHeight }
+
+        val position: Offset
+        if (caretType == CaretType.Plain) {
+            position =
+                if (anchorMid + tooltipWidth / 2 > windowContainerWidthInPx) {
+                    // Caret needs to be near the right
+                    val anchorMidFromRightScreenEdge =
+                        windowContainerWidthInPx - anchorMid
+                    val caretX = tooltipWidth - anchorMidFromRightScreenEdge
+                    Offset(caretX, caretY)
+                } else {
+                    // Caret needs to be near the left
+                    val tooltipLeft =
+                        anchorLeft - (this.size.width / 2 - anchorWidth / 2)
+                    val caretX = anchorMid - maxOf(tooltipLeft, 0f)
+                    Offset(caretX, caretY)
+                }
+        } else {
+            // Default the caret to the left
+            var preferredPosition = Offset(anchorMid - anchorLeft, caretY)
+            if (anchorLeft + tooltipWidth > windowContainerWidthInPx) {
+                // Need to move the caret to the right
+                preferredPosition = Offset(anchorMid - (anchorRight - tooltipWidth), caretY)
+                if (anchorRight - tooltipWidth < 0) {
+                    // Need to center the caret
+                    // Caret might need to be offset depending on where
+                    // the tooltip is placed relative to the anchor
+                    if (anchorLeft - tooltipWidth / 2 + anchorWidth / 2 <= 0) {
+                        preferredPosition = Offset(anchorMid, caretY)
+                    } else if (
+                        anchorRight + tooltipWidth / 2 - anchorWidth / 2 >= windowContainerWidthInPx
+                    ) {
+                        val anchorMidFromRightScreenEdge =
+                            windowContainerWidthInPx - anchorMid
+                        val caretX = tooltipWidth - anchorMidFromRightScreenEdge
+                        preferredPosition = Offset(caretX, caretY)
+                    } else {
+                        preferredPosition = Offset(tooltipWidth / 2, caretY)
+                    }
+                }
+            }
+            position = preferredPosition
+        }
+
+        if (isCaretTop) {
+            path.apply {
+                moveTo(x = position.x, y = position.y)
+                lineTo(x = position.x + caretWidthPx / 2, y = position.y)
+                lineTo(x = position.x, y = position.y - caretHeightPx)
+                lineTo(x = position.x - caretWidthPx / 2, y = position.y)
+                close()
+            }
+        } else {
+            path.apply {
+                moveTo(x = position.x, y = position.y)
+                lineTo(x = position.x + caretWidthPx / 2, y = position.y)
+                lineTo(x = position.x, y = position.y + caretHeightPx.toFloat())
+                lineTo(x = position.x - caretWidthPx / 2, y = position.y)
+                close()
+            }
+        }
+    }
+
+    return onDrawWithContent {
+        if (anchorLayoutCoordinates != null) {
+            drawContent()
+            drawPath(
+                path = path,
+                color = containerColor
+            )
+        }
+    }
+}
+
+@ExperimentalMaterial3Api
+private enum class CaretType {
+    Plain, Rich
+}
+
+@Composable
+internal expect fun windowContainerWidthInPx(): Int
+
 internal val SpacingBetweenTooltipAndAnchor = 4.dp
 internal val TooltipMinHeight = 24.dp
 internal val TooltipMinWidth = 40.dp
diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/Tooltip.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/Tooltip.desktop.kt
index 71f431b..c3cbf05 100644
--- a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/Tooltip.desktop.kt
+++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material3/Tooltip.desktop.kt
@@ -16,158 +16,12 @@
 
 package androidx.compose.material3
 
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.paddingFromBaseline
-import androidx.compose.foundation.layout.requiredHeightIn
-import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.material3.tokens.PlainTooltipTokens
-import androidx.compose.material3.tokens.RichTooltipTokens
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.LocalComposeScene
 
-/**
- * Plain tooltip that provides a descriptive message.
- *
- * Usually used with [TooltipBox].
- *
- * @param modifier the [Modifier] to be applied to the tooltip.
- * @param caretSize [DpSize] for the caret of the tooltip, if a default
- * caret is desired with a specific dimension. Please see [TooltipDefaults.caretSize] to
- * see the default dimensions. Pass in Dp.Unspecified for this parameter if no caret is desired.
- * @param shape the [Shape] that should be applied to the tooltip container.
- * @param contentColor [Color] that will be applied to the tooltip's content.
- * @param containerColor [Color] that will be applied to the tooltip's container.
- * @param tonalElevation the tonal elevation of the tooltip.
- * @param shadowElevation the shadow elevation of the tooltip.
- * @param content the composable that will be used to populate the tooltip's content.
- */
 @Composable
-@ExperimentalMaterial3Api
-actual fun TooltipScope.PlainTooltip(
-    modifier: Modifier,
-    caretSize: DpSize,
-    shape: Shape,
-    contentColor: Color,
-    containerColor: Color,
-    tonalElevation: Dp,
-    shadowElevation: Dp,
-    content: @Composable () -> Unit
-) {
-    Surface(
-        modifier = modifier,
-        shape = shape,
-        color = containerColor,
-        tonalElevation = tonalElevation,
-        shadowElevation = shadowElevation
-    ) {
-        Box(modifier = Modifier
-            .sizeIn(
-                minWidth = TooltipMinWidth,
-                maxWidth = PlainTooltipMaxWidth,
-                minHeight = TooltipMinHeight
-            )
-            .padding(PlainTooltipContentPadding)
-        ) {
-            val textStyle = PlainTooltipTokens.SupportingTextFont.value
-            CompositionLocalProvider(
-                LocalContentColor provides contentColor,
-                LocalTextStyle provides textStyle,
-                content = content
-            )
-        }
-    }
-}
-
-/**
- * Rich text tooltip that allows the user to pass in a title, text, and action.
- * Tooltips are used to provide a descriptive message.
- *
- * Usually used with [TooltipBox]
- *
- * @param modifier the [Modifier] to be applied to the tooltip.
- * @param title An optional title for the tooltip.
- * @param action An optional action for the tooltip.
- * @param caretSize [DpSize] for the caret of the tooltip, if a default
- * caret is desired with a specific dimension. Please see [TooltipDefaults.caretSize] to
- * see the default dimensions. Pass in Dp.Unspecified for this parameter if no caret is desired.
- * @param shape the [Shape] that should be applied to the tooltip container.
- * @param colors [RichTooltipColors] that will be applied to the tooltip's container and content.
- * @param tonalElevation the tonal elevation of the tooltip.
- * @param shadowElevation the shadow elevation of the tooltip.
- * @param text the composable that will be used to populate the rich tooltip's text.
- */
-@Composable
-@ExperimentalMaterial3Api
-actual fun TooltipScope.RichTooltip(
-    modifier: Modifier,
-    title: (@Composable () -> Unit)?,
-    action: (@Composable () -> Unit)?,
-    caretSize: DpSize,
-    shape: Shape,
-    colors: RichTooltipColors,
-    tonalElevation: Dp,
-    shadowElevation: Dp,
-    text: @Composable () -> Unit
-) {
-    Surface(
-        modifier = modifier
-            .sizeIn(
-                minWidth = TooltipMinWidth,
-                maxWidth = RichTooltipMaxWidth,
-                minHeight = TooltipMinHeight
-            ),
-        shape = shape,
-        color = colors.containerColor,
-        tonalElevation = tonalElevation,
-        shadowElevation = shadowElevation
-    ) {
-        val actionLabelTextStyle = RichTooltipTokens.ActionLabelTextFont.value
-        val subheadTextStyle = RichTooltipTokens.SubheadFont.value
-        val supportingTextStyle = RichTooltipTokens.SupportingTextFont.value
-
-        Column(
-            modifier = Modifier.padding(horizontal = RichTooltipHorizontalPadding)
-        ) {
-            title?.let {
-                Box(
-                    modifier = Modifier.paddingFromBaseline(top = HeightToSubheadFirstLine)
-                ) {
-                    CompositionLocalProvider(
-                        LocalContentColor provides colors.titleContentColor,
-                        LocalTextStyle provides subheadTextStyle,
-                        content = it
-                    )
-                }
-            }
-            Box(
-                modifier = Modifier.textVerticalPadding(title != null, action != null)
-            ) {
-                CompositionLocalProvider(
-                    LocalContentColor provides colors.contentColor,
-                    LocalTextStyle provides supportingTextStyle,
-                    content = text
-                )
-            }
-            action?.let {
-                Box(
-                    modifier = Modifier
-                        .requiredHeightIn(min = ActionLabelMinHeight)
-                        .padding(bottom = ActionLabelBottomPadding)
-                ) {
-                    CompositionLocalProvider(
-                        LocalContentColor provides colors.actionContentColor,
-                        LocalTextStyle provides actionLabelTextStyle,
-                        content = it
-                    )
-                }
-            }
-        }
-    }
+internal actual fun windowContainerWidthInPx(): Int {
+    // TODO: Upstream a proper way to get this from JetBrains fork
+    //  LocalWindowInfo.current.containerSize.width
+    return LocalComposeScene.current.constraints.maxWidth
 }
diff --git a/compose/material3/material3/src/skikoMain/kotlin/androidx/compose/material3/AlertDialog.skiko.kt b/compose/material3/material3/src/skikoMain/kotlin/androidx/compose/material3/AlertDialog.skiko.kt
new file mode 100644
index 0000000..e3b2ca3
--- /dev/null
+++ b/compose/material3/material3/src/skikoMain/kotlin/androidx/compose/material3/AlertDialog.skiko.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material3
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.window.DialogProperties
+
+// Keep expect/actual for maintain binary compatibility.
+// `@file:JvmName` doesn't work here because Android and Desktop were published with different names
+// Please note that binary compatibility for Desktop is tracked only in JetBrains fork
+
+@Composable
+actual fun AlertDialog(
+    onDismissRequest: () -> Unit,
+    confirmButton: @Composable () -> Unit,
+    modifier: Modifier,
+    dismissButton: @Composable (() -> Unit)?,
+    icon: @Composable (() -> Unit)?,
+    title: @Composable (() -> Unit)?,
+    text: @Composable (() -> Unit)?,
+    shape: Shape,
+    containerColor: Color,
+    iconContentColor: Color,
+    titleContentColor: Color,
+    textContentColor: Color,
+    tonalElevation: Dp,
+    properties: DialogProperties
+): Unit = AlertDialogImpl(
+    onDismissRequest = onDismissRequest,
+    confirmButton = confirmButton,
+    modifier = modifier,
+    dismissButton = dismissButton,
+    icon = icon,
+    title = title,
+    text = text,
+    shape = shape,
+    containerColor = containerColor,
+    iconContentColor = iconContentColor,
+    titleContentColor = titleContentColor,
+    textContentColor = textContentColor,
+    tonalElevation = tonalElevation,
+    properties = properties
+)
diff --git a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/ComposeScene.skiko.kt b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/ComposeScene.skiko.kt
index 2f16c79..d510fac 100644
--- a/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/ComposeScene.skiko.kt
+++ b/compose/ui/ui/src/skikoMain/kotlin/androidx/compose/ui/ComposeScene.skiko.kt
@@ -56,7 +56,9 @@
 import kotlinx.coroutines.launch
 import org.jetbrains.skia.Canvas
 
-internal val LocalComposeScene = staticCompositionLocalOf<ComposeScene> {
+// TODO: This val should not be public!
+//  Upstream current state of [ComposeScene] from JetBrains fork
+val LocalComposeScene = staticCompositionLocalOf<ComposeScene> {
     error("CompositionLocal LocalComposeScene not provided")
 }
 
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
index aea9726..63bbd51 100644
--- a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
@@ -26,6 +26,7 @@
 import androidx.health.connect.client.changes.UpsertionChange
 import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
 import androidx.health.connect.client.readRecord
+import androidx.health.connect.client.records.BloodPressureRecord
 import androidx.health.connect.client.records.HeartRateRecord
 import androidx.health.connect.client.records.NutritionRecord
 import androidx.health.connect.client.records.StepsRecord
@@ -40,6 +41,8 @@
 import androidx.health.connect.client.time.TimeRangeFilter
 import androidx.health.connect.client.units.Energy
 import androidx.health.connect.client.units.Mass
+import androidx.health.connect.client.units.grams
+import androidx.health.connect.client.units.millimetersOfMercury
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -405,19 +408,47 @@
                     startZoneOffset = ZoneOffset.UTC,
                     endTime = START_TIME + 1.minutes,
                     endZoneOffset = ZoneOffset.UTC,
-                    transFat = Mass.grams(0.5)
+                    transFat = 0.5.grams
+                ),
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
                 )
             )
         )
 
         val aggregateResponse = healthConnectClient.aggregate(
             AggregateRequest(
-                setOf(NutritionRecord.TRANS_FAT_TOTAL),
+                setOf(
+                    BloodPressureRecord.DIASTOLIC_AVG,
+                    BloodPressureRecord.DIASTOLIC_MAX,
+                    BloodPressureRecord.DIASTOLIC_MIN,
+                    BloodPressureRecord.SYSTOLIC_AVG,
+                    BloodPressureRecord.SYSTOLIC_MAX,
+                    BloodPressureRecord.SYSTOLIC_MIN,
+                    NutritionRecord.TRANS_FAT_TOTAL
+                ),
                 TimeRangeFilter.none()
             )
         )
 
-        assertThat(aggregateResponse[NutritionRecord.TRANS_FAT_TOTAL]).isEqualTo(Mass.grams(0.5))
+        assertEquals(
+            aggregateResponse[NutritionRecord.TRANS_FAT_TOTAL] to 0.5.grams,
+            aggregateResponse[BloodPressureRecord.SYSTOLIC_AVG] to
+                120.millimetersOfMercury,
+            aggregateResponse[BloodPressureRecord.SYSTOLIC_MAX] to
+                120.millimetersOfMercury,
+            aggregateResponse[BloodPressureRecord.SYSTOLIC_MIN] to
+                120.millimetersOfMercury,
+            aggregateResponse[BloodPressureRecord.DIASTOLIC_AVG] to
+                80.millimetersOfMercury,
+            aggregateResponse[BloodPressureRecord.DIASTOLIC_MAX] to
+                80.millimetersOfMercury,
+            aggregateResponse[BloodPressureRecord.DIASTOLIC_MIN] to
+                80.millimetersOfMercury,
+        )
     }
 
     @Ignore("b/314092270")
@@ -736,6 +767,10 @@
             .containsExactlyElementsIn(allHealthPermissions)
     }
 
+    private fun <A, E> assertEquals(vararg assertions: Pair<A, E>) {
+        assertions.forEach { (actual, expected) -> assertThat(actual).isEqualTo(expected) }
+    }
+
     private val Int.seconds: Duration
         get() = Duration.ofSeconds(this.toLong())
 
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensionsTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensionsTest.kt
new file mode 100644
index 0000000..afb5722e
--- /dev/null
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensionsTest.kt
@@ -0,0 +1,539 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.connect.client.impl.platform.aggregate
+
+import android.annotation.TargetApi
+import android.content.Context
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.impl.HealthConnectClientUpsideDownImpl
+import androidx.health.connect.client.permission.HealthPermission
+import androidx.health.connect.client.records.BloodPressureRecord
+import androidx.health.connect.client.records.NutritionRecord
+import androidx.health.connect.client.records.metadata.DataOrigin
+import androidx.health.connect.client.time.TimeRangeFilter
+import androidx.health.connect.client.units.millimetersOfMercury
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.GrantPermissionRule
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class BloodPressureAggregationExtensionsTest {
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val healthConnectClient: HealthConnectClient =
+        HealthConnectClientUpsideDownImpl(context)
+
+    private companion object {
+        private val START_TIME =
+            LocalDate.now().minusDays(5).atStartOfDay().toInstant(ZoneOffset.UTC)
+    }
+
+    @get:Rule
+    val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
+        HealthPermission.getWritePermission(BloodPressureRecord::class),
+        HealthPermission.getReadPermission(BloodPressureRecord::class)
+    )
+
+    @After
+    fun tearDown() = runTest {
+        healthConnectClient.deleteRecords(BloodPressureRecord::class, TimeRangeFilter.none())
+    }
+
+    @Test
+    fun aggregateBloodPressure_invalidMetrics() = runTest {
+        val metrics = setOf(
+            BloodPressureRecord.DIASTOLIC_AVG,
+            BloodPressureRecord.DIASTOLIC_MAX,
+            BloodPressureRecord.DIASTOLIC_MIN,
+            BloodPressureRecord.SYSTOLIC_AVG,
+            BloodPressureRecord.SYSTOLIC_MAX,
+            BloodPressureRecord.SYSTOLIC_MIN,
+            NutritionRecord.TRANS_FAT_TOTAL
+        )
+
+        assertThrows(IllegalStateException::class.java) {
+            runBlocking {
+                healthConnectClient.aggregateBloodPressure(
+                    metrics,
+                    TimeRangeFilter.none(),
+                    emptySet()
+                )
+            }
+        }
+    }
+
+    @Test
+    fun aggregateBloodPressure_noFiltersNoData() = runTest {
+        val metrics = setOf(
+            BloodPressureRecord.DIASTOLIC_AVG,
+            BloodPressureRecord.DIASTOLIC_MAX,
+            BloodPressureRecord.DIASTOLIC_MIN,
+            BloodPressureRecord.SYSTOLIC_AVG,
+            BloodPressureRecord.SYSTOLIC_MAX,
+            BloodPressureRecord.SYSTOLIC_MIN,
+        )
+
+        val aggregationResult =
+            healthConnectClient.aggregateBloodPressure(metrics, TimeRangeFilter.none(), emptySet())
+
+        metrics.forEach {
+            assertThat(it in aggregationResult).isFalse()
+        }
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    @Test
+    fun aggregateBloodPressure_noFilters() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 105.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 2.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 90.millimetersOfMercury,
+                    diastolic = 70.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 6.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult =
+            healthConnectClient.aggregateBloodPressure(
+                setOf(BloodPressureRecord.SYSTOLIC_MAX),
+                TimeRangeFilter.none(), emptySet()
+            )
+
+        assertThat(aggregationResult[BloodPressureRecord.SYSTOLIC_MAX])
+            .isEqualTo(120.millimetersOfMercury)
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    @Test
+    fun aggregateBloodPressure_noFilters_allMetrics() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult =
+            healthConnectClient.aggregateBloodPressure(
+                setOf(
+                    BloodPressureRecord.DIASTOLIC_AVG,
+                    BloodPressureRecord.DIASTOLIC_MAX,
+                    BloodPressureRecord.DIASTOLIC_MIN,
+                    BloodPressureRecord.SYSTOLIC_AVG,
+                    BloodPressureRecord.SYSTOLIC_MAX,
+                    BloodPressureRecord.SYSTOLIC_MIN,
+                ),
+                TimeRangeFilter.none(), emptySet()
+            )
+
+        assertEquals(
+            aggregationResult[BloodPressureRecord.DIASTOLIC_AVG] to 70.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.DIASTOLIC_MAX] to 80.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.DIASTOLIC_MIN] to 60.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_AVG] to 110.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MAX] to 120.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MIN] to 100.millimetersOfMercury,
+        )
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    @Test
+    fun aggregateBloodPressure_noFilters_someMetrics() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult =
+            healthConnectClient.aggregateBloodPressure(
+                setOf(
+                    BloodPressureRecord.DIASTOLIC_AVG,
+                    BloodPressureRecord.SYSTOLIC_MAX,
+                    BloodPressureRecord.SYSTOLIC_MIN,
+                ),
+                TimeRangeFilter.none(), emptySet()
+            )
+
+        assertEquals(
+            aggregationResult[BloodPressureRecord.DIASTOLIC_AVG] to 70.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MAX] to 120.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MIN] to 100.millimetersOfMercury,
+        )
+        setOf(
+            BloodPressureRecord.DIASTOLIC_MAX,
+            BloodPressureRecord.DIASTOLIC_MIN,
+            BloodPressureRecord.SYSTOLIC_AVG
+        ).forEach { assertThat(it in aggregationResult).isFalse() }
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    @Test
+    fun aggregateBloodPressure_noFilters_noMetrics() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 105.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 2.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 90.millimetersOfMercury,
+                    diastolic = 70.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 6.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult =
+            healthConnectClient.aggregateBloodPressure(
+                emptySet(),
+                TimeRangeFilter.none(), emptySet()
+            )
+
+        setOf(
+            BloodPressureRecord.DIASTOLIC_AVG,
+            BloodPressureRecord.DIASTOLIC_MAX,
+            BloodPressureRecord.DIASTOLIC_MIN,
+            BloodPressureRecord.SYSTOLIC_AVG,
+            BloodPressureRecord.SYSTOLIC_MAX,
+            BloodPressureRecord.SYSTOLIC_MIN,
+        ).forEach {
+            assertThat(it in aggregationResult).isFalse()
+        }
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    @Test
+    fun aggregateBloodPressure_instantTimeRangeFilter() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 105.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 2.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 90.millimetersOfMercury,
+                    diastolic = 70.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 6.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult = healthConnectClient.aggregateBloodPressure(
+            setOf(BloodPressureRecord.DIASTOLIC_MIN),
+            TimeRangeFilter.between(
+                START_TIME + 30.seconds,
+                START_TIME + 6.minutes + 45.seconds
+            ), emptySet()
+        )
+
+        assertThat(aggregationResult[BloodPressureRecord.DIASTOLIC_MIN])
+            .isEqualTo(65.millimetersOfMercury)
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    @Test
+    fun aggregateBloodPressure_instantTimeRangeFilter_filterEndTime() =
+        runTest {
+            healthConnectClient.insertRecords(
+                listOf(
+                    BloodPressureRecord(
+                        time = START_TIME,
+                        zoneOffset = ZoneOffset.UTC,
+                        systolic = 110.millimetersOfMercury,
+                        diastolic = 65.millimetersOfMercury
+                    ),
+                    BloodPressureRecord(
+                        time = START_TIME + 2.minutes,
+                        zoneOffset = ZoneOffset.UTC,
+                        systolic = 100.millimetersOfMercury,
+                        diastolic = 80.millimetersOfMercury
+                    )
+                )
+            )
+
+            val aggregationResult = healthConnectClient.aggregateBloodPressure(
+                setOf(BloodPressureRecord.DIASTOLIC_AVG, BloodPressureRecord.SYSTOLIC_AVG),
+                TimeRangeFilter.between(
+                    START_TIME + 1.minutes,
+                    START_TIME + 1.minutes + 59.seconds
+                ), emptySet()
+            )
+
+            assertThat(BloodPressureRecord.DIASTOLIC_AVG in aggregationResult).isFalse()
+            assertThat(BloodPressureRecord.SYSTOLIC_AVG in aggregationResult).isFalse()
+            assertThat(aggregationResult.dataOrigins).isEmpty()
+        }
+
+    @Test
+    fun aggregateBloodPressure_localTimeRangeFilter() = runTest {
+        assumeTrue(SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 10)
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 105.millimetersOfMercury,
+                    diastolic = 60.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 2.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 70.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 4.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 120.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 6.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+                BloodPressureRecord(
+                    time = START_TIME + 8.minutes,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 100.millimetersOfMercury,
+                    diastolic = 80.millimetersOfMercury
+                )
+            )
+        )
+
+        val aggregationResult = healthConnectClient.aggregateBloodPressure(
+            setOf(BloodPressureRecord.DIASTOLIC_MIN, BloodPressureRecord.SYSTOLIC_AVG),
+            TimeRangeFilter.between(
+                LocalDateTime.ofInstant(
+                    START_TIME + 2.hours + 30.seconds,
+                    ZoneOffset.ofHours(-2)
+                ),
+                LocalDateTime.ofInstant(
+                    START_TIME + 2.hours + 6.minutes + 45.seconds,
+                    ZoneOffset.ofHours(-2)
+                )
+            ), emptySet()
+        )
+
+        assertThat(aggregationResult[BloodPressureRecord.DIASTOLIC_MIN])
+            .isEqualTo(65.millimetersOfMercury)
+        assertThat(aggregationResult[BloodPressureRecord.SYSTOLIC_AVG])
+            .isEqualTo(110.millimetersOfMercury)
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    // TODO(b/337195270): Test with data origins from multiple apps
+    @Test
+    fun aggregateBloodPressure_insertedDataOriginFilter() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+            )
+        )
+
+        val aggregationResult = healthConnectClient.aggregateBloodPressure(
+            setOf(BloodPressureRecord.SYSTOLIC_AVG),
+            TimeRangeFilter.none(),
+            setOf(DataOrigin(context.packageName))
+        )
+
+        assertThat(aggregationResult[BloodPressureRecord.SYSTOLIC_AVG])
+            .isEqualTo(110.millimetersOfMercury)
+        assertThat(aggregationResult.dataOrigins)
+            .containsExactly(DataOrigin(context.packageName))
+    }
+
+    @Test
+    fun aggregateBloodPressure_timeRangeFilterOutOfBounds() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+            )
+        )
+
+        val aggregationResult = healthConnectClient.aggregateBloodPressure(
+            setOf(BloodPressureRecord.SYSTOLIC_AVG),
+            TimeRangeFilter.after(START_TIME + 2.minutes),
+            emptySet()
+        )
+
+        assertThat(BloodPressureRecord.SYSTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    @Test
+    fun aggregateBloodPressure_nonExistingDataOriginFilter() = runTest {
+        healthConnectClient.insertRecords(
+            listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    systolic = 110.millimetersOfMercury,
+                    diastolic = 65.millimetersOfMercury
+                ),
+            )
+        )
+
+        val aggregationResult = healthConnectClient.aggregateBloodPressure(
+            setOf(BloodPressureRecord.SYSTOLIC_AVG),
+            TimeRangeFilter.none(),
+            setOf(DataOrigin("some random package name"))
+        )
+
+        assertThat(BloodPressureRecord.SYSTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    private fun <A, E> assertEquals(vararg assertions: Pair<A, E>) {
+        assertions.forEach { (actual, expected) -> assertThat(actual).isEqualTo(expected) }
+    }
+
+    private val Int.seconds: Duration
+        get() = Duration.ofSeconds(this.toLong())
+
+    private val Int.minutes: Duration
+        get() = Duration.ofMinutes(this.toLong())
+
+    private val Int.hours: Duration
+        get() = Duration.ofHours(this.toLong())
+}
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensionsTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensionsTest.kt
index 78225d6..76952af 100644
--- a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensionsTest.kt
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensionsTest.kt
@@ -23,12 +23,14 @@
 import androidx.health.connect.client.HealthConnectClient
 import androidx.health.connect.client.impl.HealthConnectClientUpsideDownImpl
 import androidx.health.connect.client.permission.HealthPermission
+import androidx.health.connect.client.records.BloodPressureRecord
 import androidx.health.connect.client.records.NutritionRecord
 import androidx.health.connect.client.records.StepsRecord
 import androidx.health.connect.client.records.metadata.DataOrigin
 import androidx.health.connect.client.request.AggregateRequest
 import androidx.health.connect.client.time.TimeRangeFilter
-import androidx.health.connect.client.units.Mass
+import androidx.health.connect.client.units.grams
+import androidx.health.connect.client.units.millimetersOfMercury
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -65,6 +67,8 @@
 
     @get:Rule
     val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
+        HealthPermission.getWritePermission(BloodPressureRecord::class),
+        HealthPermission.getReadPermission(BloodPressureRecord::class),
         HealthPermission.getWritePermission(NutritionRecord::class),
         HealthPermission.getReadPermission(NutritionRecord::class),
         HealthPermission.getWritePermission(StepsRecord::class),
@@ -83,11 +87,17 @@
 
         healthConnectClient.insertRecords(
             listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    diastolic = 70.millimetersOfMercury,
+                    systolic = 110.millimetersOfMercury
+                ),
                 NutritionRecord(
                     startTime = START_TIME,
                     endTime = START_TIME + 1.minutes,
-                    transFat = Mass.grams(0.3),
-                    calcium = Mass.grams(0.1),
+                    transFat = 0.3.grams,
+                    calcium = 0.1.grams,
                     startZoneOffset = ZoneOffset.UTC,
                     endZoneOffset = ZoneOffset.UTC
                 )
@@ -95,14 +105,30 @@
         )
 
         val aggregationResult =
-            healthConnectClient.aggregateFallback(AggregateRequest(
-                metrics = setOf(NutritionRecord.TRANS_FAT_TOTAL, NutritionRecord.CALCIUM_TOTAL),
-                timeRangeFilter = TimeRangeFilter.none()
-            ))
+            healthConnectClient.aggregateFallback(
+                AggregateRequest(
+                    metrics = setOf(
+                        BloodPressureRecord.DIASTOLIC_AVG,
+                        BloodPressureRecord.DIASTOLIC_MAX,
+                        BloodPressureRecord.DIASTOLIC_MIN,
+                        BloodPressureRecord.SYSTOLIC_AVG,
+                        BloodPressureRecord.SYSTOLIC_MAX,
+                        BloodPressureRecord.SYSTOLIC_MIN,
+                        NutritionRecord.TRANS_FAT_TOTAL,
+                        NutritionRecord.CALCIUM_TOTAL
+                    ),
+                    timeRangeFilter = TimeRangeFilter.none()
+                )
+            )
 
+        assertThat(BloodPressureRecord.DIASTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.DIASTOLIC_MAX in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.DIASTOLIC_MIN in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_MAX in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_MIN in aggregationResult).isFalse()
         assertThat(NutritionRecord.TRANS_FAT_TOTAL in aggregationResult).isFalse()
         assertThat(NutritionRecord.CALCIUM_TOTAL in aggregationResult).isFalse()
-
         assertThat(aggregationResult.dataOrigins).isEmpty()
     }
 
@@ -112,11 +138,17 @@
 
         healthConnectClient.insertRecords(
             listOf(
+                BloodPressureRecord(
+                    time = START_TIME,
+                    zoneOffset = ZoneOffset.UTC,
+                    diastolic = 70.millimetersOfMercury,
+                    systolic = 110.millimetersOfMercury
+                ),
                 NutritionRecord(
                     startTime = START_TIME,
                     endTime = START_TIME + 1.minutes,
-                    transFat = Mass.grams(0.3),
-                    calcium = Mass.grams(0.1),
+                    transFat = 0.3.grams,
+                    calcium = 0.1.grams,
                     startZoneOffset = ZoneOffset.UTC,
                     endZoneOffset = ZoneOffset.UTC
                 )
@@ -124,19 +156,69 @@
         )
 
         val aggregationResult =
-            healthConnectClient.aggregateFallback(AggregateRequest(
-                metrics = setOf(NutritionRecord.TRANS_FAT_TOTAL, NutritionRecord.CALCIUM_TOTAL),
-                timeRangeFilter = TimeRangeFilter.none()
-            ))
+            healthConnectClient.aggregateFallback(
+                AggregateRequest(
+                    metrics = setOf(
+                        NutritionRecord.TRANS_FAT_TOTAL,
+                        NutritionRecord.CALCIUM_TOTAL,
+                        BloodPressureRecord.DIASTOLIC_AVG,
+                        BloodPressureRecord.DIASTOLIC_MAX,
+                        BloodPressureRecord.DIASTOLIC_MIN,
+                        BloodPressureRecord.SYSTOLIC_AVG,
+                        BloodPressureRecord.SYSTOLIC_MAX,
+                        BloodPressureRecord.SYSTOLIC_MIN,
+                    ),
+                    timeRangeFilter = TimeRangeFilter.none()
+                )
+            )
 
-        assertThat(aggregationResult[NutritionRecord.TRANS_FAT_TOTAL]).isEqualTo(Mass.grams(0.3))
-        assertThat(NutritionRecord.CALCIUM_TOTAL in aggregationResult).isFalse()
-
+        assertEquals(
+            aggregationResult[BloodPressureRecord.DIASTOLIC_AVG] to 70.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.DIASTOLIC_MAX] to 70.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.DIASTOLIC_MIN] to 70.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_AVG] to 110.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MAX] to 110.millimetersOfMercury,
+            aggregationResult[BloodPressureRecord.SYSTOLIC_MIN] to 110.millimetersOfMercury,
+            aggregationResult[NutritionRecord.TRANS_FAT_TOTAL] to 0.3.grams,
+            (NutritionRecord.CALCIUM_TOTAL in aggregationResult) to false,
+        )
         assertThat(aggregationResult.dataOrigins)
             .containsExactly(DataOrigin(context.packageName))
     }
 
     @Test
+    fun aggregateFallback_belowSdkExt10NoData() = runTest {
+        assumeFalse(SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 10)
+
+        val aggregationResult =
+            healthConnectClient.aggregateFallback(
+                AggregateRequest(
+                    metrics = setOf(
+                        BloodPressureRecord.DIASTOLIC_AVG,
+                        BloodPressureRecord.DIASTOLIC_MAX,
+                        BloodPressureRecord.DIASTOLIC_MIN,
+                        BloodPressureRecord.SYSTOLIC_AVG,
+                        BloodPressureRecord.SYSTOLIC_MAX,
+                        BloodPressureRecord.SYSTOLIC_MIN,
+                        NutritionRecord.TRANS_FAT_TOTAL,
+                        NutritionRecord.CALCIUM_TOTAL
+                    ),
+                    timeRangeFilter = TimeRangeFilter.none()
+                )
+            )
+
+        assertThat(BloodPressureRecord.DIASTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.DIASTOLIC_MAX in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.DIASTOLIC_MIN in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_AVG in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_MAX in aggregationResult).isFalse()
+        assertThat(BloodPressureRecord.SYSTOLIC_MIN in aggregationResult).isFalse()
+        assertThat(NutritionRecord.TRANS_FAT_TOTAL in aggregationResult).isFalse()
+        assertThat(NutritionRecord.CALCIUM_TOTAL in aggregationResult).isFalse()
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    @Test
     fun readRecordsFlow_noFilters_readsAllInsertedRecords() = runTest {
         insertManyStepsRecords()
 
@@ -214,6 +296,10 @@
         }
     }
 
+    private fun <A, E> assertEquals(vararg assertions: Pair<A, E>) {
+        assertions.forEach { (actual, expected) -> assertThat(actual).isEqualTo(expected) }
+    }
+
     private val Int.seconds: Duration
         get() = Duration.ofSeconds(this.toLong())
 
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/NutritionAggregationExtensionsTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/NutritionAggregationExtensionsTest.kt
index db17e4f..27e1d07 100644
--- a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/NutritionAggregationExtensionsTest.kt
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/platform/aggregate/NutritionAggregationExtensionsTest.kt
@@ -69,6 +69,15 @@
     }
 
     @Test
+    fun aggregateNutritionTransFatTotal_noData() = runTest {
+        val aggregationResult =
+            healthConnectClient.aggregateNutritionTransFatTotal(TimeRangeFilter.none(), emptySet())
+
+        assertThat(NutritionRecord.TRANS_FAT_TOTAL in aggregationResult).isFalse()
+        assertThat(aggregationResult.dataOrigins).isEmpty()
+    }
+
+    @Test
     fun aggregateNutritionTransFatTotal_noFilters() = runTest {
         healthConnectClient.insertRecords(
             listOf(
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensions.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensions.kt
new file mode 100644
index 0000000..d8181f5
--- /dev/null
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/BloodPressureAggregationExtensions.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:RequiresApi(api = 34)
+
+package androidx.health.connect.client.impl.platform.aggregate
+
+import androidx.annotation.RequiresApi
+import androidx.health.connect.client.HealthConnectClient
+import androidx.health.connect.client.aggregate.AggregateMetric
+import androidx.health.connect.client.aggregate.AggregationResult
+import androidx.health.connect.client.records.BloodPressureRecord
+import androidx.health.connect.client.records.metadata.DataOrigin
+import androidx.health.connect.client.time.TimeRangeFilter
+import androidx.health.connect.client.units.Pressure
+import kotlin.math.max
+import kotlin.math.min
+
+private val BLOOD_PRESSURE_METRICS = setOf(
+    BloodPressureRecord.DIASTOLIC_AVG,
+    BloodPressureRecord.DIASTOLIC_MAX,
+    BloodPressureRecord.DIASTOLIC_MIN,
+    BloodPressureRecord.SYSTOLIC_AVG,
+    BloodPressureRecord.SYSTOLIC_MAX,
+    BloodPressureRecord.SYSTOLIC_MIN,
+)
+
+internal suspend fun HealthConnectClient.aggregateBloodPressure(
+    bloodPressureMetrics: Set<AggregateMetric<*>>,
+    timeRangeFilter: TimeRangeFilter,
+    dataOriginFilter: Set<DataOrigin>
+): AggregationResult {
+    check(BLOOD_PRESSURE_METRICS.containsAll(bloodPressureMetrics)) {
+        "Invalid set of blood pressure metrics $bloodPressureMetrics"
+    }
+
+    if (bloodPressureMetrics.isEmpty()) {
+        return emptyAggregationResult()
+    }
+
+    val readRecordsFlow = readRecordsFlow(
+        BloodPressureRecord::class,
+        timeRangeFilter,
+        dataOriginFilter
+    )
+
+    val avgDataMap = mutableMapOf<AggregateMetric<Pressure>, AvgData>()
+    val minMaxMap = mutableMapOf<AggregateMetric<Pressure>, Double?>()
+
+    for (metric in bloodPressureMetrics) {
+        when (metric) {
+            BloodPressureRecord.DIASTOLIC_AVG, BloodPressureRecord.SYSTOLIC_AVG ->
+                avgDataMap[metric] = AvgData()
+
+            BloodPressureRecord.DIASTOLIC_MAX, BloodPressureRecord.DIASTOLIC_MIN,
+            BloodPressureRecord.SYSTOLIC_MAX, BloodPressureRecord.SYSTOLIC_MIN ->
+                minMaxMap[metric] = null
+
+            else -> error("Invalid blood pressure fallback aggregation type ${metric.metricKey}")
+        }
+    }
+
+    val dataOrigins = mutableSetOf<DataOrigin>()
+
+    readRecordsFlow.collect { records ->
+        records.forEach {
+            val diastolic = it.diastolic.inMillimetersOfMercury
+            val systolic = it.systolic.inMillimetersOfMercury
+
+            for (metric in bloodPressureMetrics) {
+                when (metric) {
+                    BloodPressureRecord.DIASTOLIC_AVG -> avgDataMap[metric]!! += diastolic
+                    BloodPressureRecord.DIASTOLIC_MAX -> minMaxMap[metric] =
+                        max(minMaxMap[metric] ?: diastolic, diastolic)
+
+                    BloodPressureRecord.DIASTOLIC_MIN -> minMaxMap[metric] =
+                        min(minMaxMap[metric] ?: diastolic, diastolic)
+
+                    BloodPressureRecord.SYSTOLIC_AVG -> avgDataMap[metric]!! += systolic
+                    BloodPressureRecord.SYSTOLIC_MAX -> minMaxMap[metric] =
+                        max(minMaxMap[metric] ?: systolic, systolic)
+
+                    BloodPressureRecord.SYSTOLIC_MIN -> minMaxMap[metric] =
+                        min(minMaxMap[metric] ?: systolic, systolic)
+                }
+            }
+
+            dataOrigins += it.metadata.dataOrigin
+        }
+    }
+
+    if (dataOrigins.isEmpty()) {
+        return emptyAggregationResult()
+    }
+
+    val doubleValues = buildMap {
+        for (metric in bloodPressureMetrics) {
+            val aggregatedValue = when (metric) {
+                BloodPressureRecord.DIASTOLIC_AVG, BloodPressureRecord.SYSTOLIC_AVG ->
+                    avgDataMap[metric]!!.average()
+
+                BloodPressureRecord.DIASTOLIC_MAX, BloodPressureRecord.DIASTOLIC_MIN,
+                BloodPressureRecord.SYSTOLIC_MAX, BloodPressureRecord.SYSTOLIC_MIN ->
+                    minMaxMap[metric]!!
+
+                else ->
+                    error("Invalid blood pressure fallback aggregation type ${metric.metricKey}")
+            }
+
+            put(metric.metricKey, aggregatedValue)
+        }
+    }
+
+    return AggregationResult(
+        longValues = mapOf(),
+        doubleValues = doubleValues,
+        dataOrigins = dataOrigins
+    )
+}
+
+private data class AvgData(var count: Int = 0, var total: Double = 0.0) {
+    operator fun plusAssign(value: Double) {
+        count++
+        total += value
+    }
+
+    fun average() = total / count
+}
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensions.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensions.kt
index 5a45b8b..a659c1b 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensions.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/platform/aggregate/HealthConnectClientAggregationExtensions.kt
@@ -48,45 +48,55 @@
 // Max buffer to account for overlapping records that have startTime < timeRangeFilter.startTime
 val RECORD_START_TIME_BUFFER: Duration = Duration.ofDays(1)
 
+private val AGGREGATION_FALLBACK_RECORD_TYPES = setOf(
+    BloodPressureRecord::class,
+    CyclingPedalingCadenceRecord::class,
+    NutritionRecord::class,
+    SpeedRecord::class,
+    StepsCadenceRecord::class
+)
+
 internal suspend fun HealthConnectClient.aggregateFallback(request: AggregateRequest):
     AggregationResult {
-    return request.fallbackMetrics
-        .fold(emptyAggregationResult()) { currentAggregateResult, metric ->
-            currentAggregateResult + aggregate(
-                metric,
-                request.timeRangeFilter,
-                request.dataOriginFilter
-            )
-        }
+    var aggregationResult = emptyAggregationResult()
+
+    for (recordType in AGGREGATION_FALLBACK_RECORD_TYPES) {
+        aggregationResult += aggregate(
+            recordType,
+            request.fallbackMetrics,
+            request.timeRangeFilter,
+            request.dataOriginFilter
+        )
+    }
+
+    return aggregationResult
 }
 
-private suspend fun <T : Any> HealthConnectClient.aggregate(
-    metric: AggregateMetric<T>,
+private suspend fun <T : Record> HealthConnectClient.aggregate(
+    recordType: KClass<T>,
+    metrics: Set<AggregateMetric<*>>,
     timeRangeFilter: TimeRangeFilter,
     dataOriginFilter: Set<DataOrigin>
 ): AggregationResult {
-    return when (metric) {
-        NutritionRecord.TRANS_FAT_TOTAL -> aggregateNutritionTransFatTotal(
+    val dataTypeName = recordType.simpleName!!.replace("Record", "")
+    val recordTypeMetrics = metrics.filter { it.dataTypeName == dataTypeName }.toSet()
+
+    if (recordTypeMetrics.isEmpty()) {
+        return emptyAggregationResult()
+    }
+
+    return when (recordType) {
+        BloodPressureRecord::class -> aggregateBloodPressure(
+            recordTypeMetrics,
             timeRangeFilter,
             dataOriginFilter
         )
 
-        BloodPressureRecord.DIASTOLIC_AVG -> TODO(reason = "b/326414908")
-        BloodPressureRecord.DIASTOLIC_MAX -> TODO(reason = "b/326414908")
-        BloodPressureRecord.DIASTOLIC_MIN -> TODO(reason = "b/326414908")
-        BloodPressureRecord.SYSTOLIC_AVG -> TODO(reason = "b/326414908")
-        BloodPressureRecord.SYSTOLIC_MAX -> TODO(reason = "b/326414908")
-        BloodPressureRecord.SYSTOLIC_MIN -> TODO(reason = "b/326414908")
-        CyclingPedalingCadenceRecord.RPM_AVG -> TODO(reason = "b/326414908")
-        CyclingPedalingCadenceRecord.RPM_MAX -> TODO(reason = "b/326414908")
-        CyclingPedalingCadenceRecord.RPM_MIN -> TODO(reason = "b/326414908")
-        SpeedRecord.SPEED_AVG -> TODO(reason = "b/326414908")
-        SpeedRecord.SPEED_MAX -> TODO(reason = "b/326414908")
-        SpeedRecord.SPEED_MIN -> TODO(reason = "b/326414908")
-        StepsCadenceRecord.RATE_AVG -> TODO(reason = "b/326414908")
-        StepsCadenceRecord.RATE_MAX -> TODO(reason = "b/326414908")
-        StepsCadenceRecord.RATE_MIN -> TODO(reason = "b/326414908")
-        else -> error("Invalid fallback aggregation type ${metric.metricKey}")
+        CyclingPedalingCadenceRecord::class -> TODO(reason = "b/326414908")
+        NutritionRecord::class -> aggregateNutritionTransFatTotal(timeRangeFilter, dataOriginFilter)
+        SpeedRecord::class -> TODO(reason = "b/326414908")
+        StepsCadenceRecord::class -> TODO(reason = "b/326414908")
+        else -> error("Invalid record type for aggregation fallback: $recordType")
     }
 }
 
@@ -165,7 +175,7 @@
 internal fun emptyAggregationResult() =
     AggregationResult(longValues = mapOf(), doubleValues = mapOf(), dataOrigins = setOf())
 
-internal data class AggregatedData<T>(
+class AggregatedData<T>(
     var value: T,
     var dataOrigins: MutableSet<DataOrigin> = mutableSetOf()
 )